【问题标题】:Looking for recipe: Multiple async Ajax requests in JavaScript寻找秘诀:JavaScript 中的多个异步 Ajax 请求
【发布时间】:2011-04-11 18:02:45
【问题描述】:

我将花费大量时间来解决一个问题,我想知道是否有现成的解决方法。它是一个基于浏览器的应用程序(JavaScript 和 Dojo Toolkit),是 RESTful Web 服务的客户端。

它使用 Comet 自动更新显示。有一个回调函数处理收到的每条消息。 [Comet 的无聊细节:作为一种后台操作,向服务器发出 HTTP 请求。这个请求在服务器上阻塞,直到它有消息给我们。当客户端最终收到响应时,它会调用回调函数,然后发出下一个 HTTP 请求。 HTTP 最多允许两个同时请求,因此这个“后台”请求不会阻止用户执行操作时发生的“前台”请求。]

在 UI 层下面有一个适配器层。 UI 层认为它正在将消息推送给它。适配器层执行 Comet 请求并将响应从服务器发送的内容转换为 UI 层所期望的内容。

var ourEventFilter = dojo.hitch(this, function(evt) {
  if (evt["obj"]) {
        evt.obj = this.transform(evt.obj);
  }
  callUIEventHandler(evt);
}

[dojo.hitch() 是一个语法糖,用来做一个闭包,绑定一个函数的this.]

obj 可能看起来像这样:

{
   "resources": [
      {"name":"Me", "type":"vm", "link":"http://server/item/ABC"},
      {"name":"You", "type":"real", "link":"http://server/item/123"}],
   "subObjs": [
      "resources":[{"name":"Him", "type":"vm", "link":"http://server/item/DEF"} 
   ]
}

transform 函数把它变成这样:

{
   "resources": [
      {"name":"You", "type":"real", "link":"http://server/item/123"},
  ],
   "vms": [
      {"name":"Me", "type":"vm", "link":"http://server/item/ABC"}],
   "subObjs:" [
      "resources":[],
      "vms": [{"name":"Him","type":"vm", "link":"http://server/item/DEF"}]
   ]
}

我们找到那些“vm”类型的“资源”并将它们移动到一个单独的数组中。到目前为止,一切都很好。变换函数很简单。它是递归的,因为 subOjbs 可以包含 subObjs。

但是现在我们需要更多关于虚拟机的信息。我们需要对服务器进行 Ajax 调用以获取此信息:

{
   "resources": [
      {"name":"You", "type":"real", "link":"http://server/item/123"}],
   "vms": [
      {"name":"Me", "type":"vm", "link":"http://server/item/ABC", "moreInfo":"X"}],
   "subObjs:" [
      "resources":[],
      "vms": [{"name":"Him","type":"vm", "link":"http://server/item/DEF", 
                "moreInfo":"Y"}]
   ]
}

变换函数看起来像这样:

transform: function(obj) {
      var vms=[];
      var newResources = [];
      // Recurse on subObjs
      if (obj.subObjs) {
         for (var kx = 0; kx < obj.subObjs.length; kx++) {
            ojb.subObjs[kx] = this.transform(obj.subObjs[kx]);
      }
      // Move vms out of resources into vms
      if (obj.resources) {
         for (var jx = 0; jx < obj.resources.length; jx++) {
            if (obj.resources[jx].type == "vm") {
               var thisVM = obj.resources[jx];
               // Note:  more info needed here.
               //thisVM = this.getMoreInfo(thisVM);
               vms.push(thisVM);
            } else { 
               newResources.push(obj.resources[jx];
            }
         }
         obj.vms = vms;
         obj.resources = newResources;
      }
      return obj;
}

现在我们遇到了一个问题。 getMoreInfo() 怎么写?

此时我可以进行同步调用:

getMoreInfo: function(vm) {
   vmObj = callServerSynchronouslyToGET(vm.link);
   vm.moreInfo = vmObj ? vmObj.moreInfo : null;
}

但是在 Ajax 中同步调用从来都不是一个好主意(应该是 Sjax)。

我认为编写 getMoreInfo() 来进行异步调用是不可能的。我必须回到洋葱的几层并从某个点向下重写所有内容,我希望不要重写 Comet-callback 层之上的任何内容。

我知道一个将递归函数转换为非递归函数的方法。有没有一种方法可以将带有以同步 GET 为中心的循环的洋葱转换为异步 GET 链?

【问题讨论】:

  • “HTTP 最多允许两个同时请求”:是的,但实际上大多数现代浏览器允许两个以上同时请求:spasche.net/files/parallel_connections“它会是 Sjax”:实际上,它会是 'Sjaj ',因为这里不涉及 XML,而是 JSON。 ;) 顺便说一句,在您的示例中,条件evt.obj["type"](还请注意缺少的括号)与evt.obj.type 相同,将始终返回false,因为type 不是evt.obj 的直接后代。
  • 另请注意,当evt.obj.type 包含一个虚假值(包括一个空字符串)时,您的条件语句块可能会被错误地跳过。请注意您使用的唯一item 对象,应该是obj
  • 代码是从真实代码简化而来的。转录中出现了一些错误。 (我改了名字,但没听清。)
  • 比同时请求的数量更重要的是,当您发出同步请求而不是异步请求时,浏览器中会发生什么。它会阻塞。
  • 我不完全确定我是否理解您对多个 同步 XMLHttpRequests 的问题,但您不能只发出一个异步请求并让回调函数实例化一个新请求成功了吗?

标签: javascript ajax rest function


【解决方案1】:

JavaScript 语言有一个跨浏览器扩展,称为 StratifiedJS。

它旨在准确解决您提到的问题:它允许您以同步方式编程,所有内容都在后台异步执行。

在浏览器上启用 StratifiedJS 的 JS 库称为“Oni Apollo”。详情请见http://onilabs.com/apollo

在您的特定情况下,您可以使用 StratifiedJS 将整个异步洋葱转换为同步代码,或者您可以通过将现有逻辑粘贴到“text/sjs”脚本元素中来保留现有逻辑:

<script src="http://code.onilabs.com/latest/oni-apollo.js"></script>

<script type="text/sjs">

  // your existing code here

  getMoreInfo: function(vm) {
    var vmObj = require('http').get(vm.link);
    vm.moreInfo = vmObj ? vmObj.moreInfo : null;
  }
</script>

这里,require('http').get() 在后台执行异步 XHR(有关详细信息,请参阅上述链接中的 apollo api 文档)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-17
    • 2023-04-01
    • 2012-05-26
    • 2018-04-10
    • 1970-01-01
    相关资源
    最近更新 更多