寻找食谱:JavaScript中的多个异步Ajax请求

时间:2010-09-13 15:52:04

标签: javascript ajax rest function

我将花费大量时间来解决问题,我想知道是否有现成的配方。它是一个基于浏览器的应用程序(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"} 
   ]
}

转换函数将其转换为:

{
   "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。

但现在我们需要有关vms的更多信息。我们需要对服务器进行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链?

1 个答案:

答案 0 :(得分: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文档)。