2011-08-08 27 views
13

我想知道如何在n组中做ajax调用。如何在jQuery中批量处理ajax请求?

这里是我的使用案例:

我有一个表显示使用情况数据。您可以钻取每一行,并且如果每行都有一个可以深入钻取的公共属性,则可以选择一次钻取所有这些属性。对于每一行,都会调用ajax来获取要附加到表中的数据。

在某些情况下,最多可同时钻取50行。正如你可以想象的那样,这给服务器带来了很大的压力。如何以最佳方式将这些电话以较小的批次发送,然后再等待批量发出?

我知道有像jquery消息队列这样的插件能够帮助我,但这是一个工作项目,所以我们希望尽可能地避免插件。

+1

因此使自己的队列管理器:) –

+0

这个答案通常有助于http://stackoverflow.com/questions/42425885/trying-to-make-2-ajax -calls-via-jquery-and-then-prepending-the-data-taken-from/42426722#42426722 –

回答

16

你可以看看使用jQuery.when,它允许您在所有请求完成时执行回调函数。

$.when($.ajax("request1"), $.ajax("request2"), $.ajax("request3")) 
.done(function(data1, data2, data3){ 
     // Do something with the data 
}); 

或者

$.when($.ajax("request1"), $.ajax("request2"), $.ajax("request3")) 
.then(successCallback, errorHandler); 

有关更多信息,请参阅以下post

此外,我不确定您对使用插件的理解应该受到您处于工作环境中的事实的影响,尤其是如果它简化了您的工作。因此可以提高生产力。当然,你必须仔细选择你的插件,因为质量和长期维护可能是一个问题。

+1

jQuery [Deferred object](http://api.jquery.com/category/deferred-object/)绝对是处理异步请求的方式。使用$ .when和$ .done处理$ .ajax承诺对象和由setTimeout产生的代码时,我的代码变得更清晰并且更具可读性。好决定。 – stinkycheeseman

+0

是理解$ .when(),但它看起来很烦琐用于我的情况,即5K xhr2查询,发送批次为50(Chrom引发SPDY服务器的内存错误),Chromium人最终会修复,但我需要调节现在。我想我可以尝试下面的递归建议。这听起来是对的吗? –

7

使用jQuery进行Ajax调用通常是异步的。因此,如果您有50行,jQuery将异步发送所有50个请求 - 当您从服务器获得响应时,您无法控制处理的顺序。

您可以在$.ajax呼叫使用async: false这样,只有一个请求是通过你的行发送到服务器,你的循环:

$.ajax({ 
    url: location, 
    data: params, 
    async: false, 
    success: function(msg) { // do something} 
}); 

这种方法(async: false)的问题是,用户可能会遇到“冻结”或无响应的页面。

另一种方法是使用递归在JavaScript,以便调用仍然异步但Ajax调用仍然等待每行类似如下的成功事件:

var maxRows = 50; 

function myFunc(index) { 
    $.ajax({ 
     url: location, 
     data: params, 
     async: true, 
     success: function(msg) { 
      if (index < maxRows) { 
       // do something 
      } 
      else { 
       return; //index equals maxRows--stop the recursion 
      } 
      index++; 
      myFunc(index); //call the function again 
     } 
    }); 

    $(document).ready(function() { 
     myFunc(0);  
    }); 
} 
+0

我需要做5K的xhr2查询,将它批量发送给50个(Chrome会引发SPDY服务器的内存错误),铬人将最终修复,但我现在需要节流。我认为你的递归方法有前途。 –

3

我同意eicto:如果您不能整合另一个,请自己创建消息管理器。这是我的一个小小的破解:

var AjaxQueue = function(max) { 
    this.max = max; 
    this.requests = []; 
    this.current = 0; 
} 

AjaxQueue.prototype.ajax = function(opts) { 
    var queue = this; 
    opts.complete = function(jqXHR, textStatus) { 
    queue.current -= 1; 
    queue.send(); 
    }; 
    this.requests.push(opts); 
    this.send(); 
} 

AjaxQueue.prototype.send = function(opts) { 
    while (this.current < this.max && this.requests.length > 0) { 
    $.ajax(this.requests.unshift()); 
    this.current += 1; 
    } 
} 

我还没有尝试过使用它,所以肯定会有错误。另外它假定你没有使用complete选项。它只是压倒它。如果你可以检查它,并确保先前的完整功能仍然被调用。

+0

啊,这很完美。我会玩弄它,看看我能做些什么。我唯一担心的是,这种情况是否存在潜在的竞争条件?我知道很少有2个Ajax调用同时完成,所以值得考虑一下吗? – stinkycheeseman

+2

否浏览器确保两个用户定义的函数不能同时运行。这就是为什么运行无限循环会锁定与网页的交互。它也使事情变得更简单。 –

+0

任何使用示例的机会? – PlanetWilson

0

调用的递归批处理适合我。但是,因为我正在获取4K的XHR2 blob并将每个节点保存在IndexedDB(PouchDB)中。我有线程为XHR2和IDB放。所以,我不得不更加复杂一点:

 for (var i in info.LayerInfo) { 
     var imageType = (info.LayerInfo[i].Class == "BASE") ? "jpg" : "png"; 
     info.LayerInfo[i].SaveCount = 0; 
     getLayer(0, info, info.LayerInfo[i], info.LayerInfo[i].Path, imageType); 
    } 
} 

function getLayer(index, info, layer, base, imageType) { 
    if (layer.Files.length == 0) { 
     console.log("Thread done: " + index + " SaveCount: " + layer.SaveCount); 
     return; 
    } 
    var val = layer.Files.shift(); 
    var path = base + "/" + val.id + "." + imageType; 
    $xhr.ajax({ 
     url: path, 
     dataType: "blob", 
     success: function (data) { 
      console.log("fetched: ", layer.Type + "-" + val.id); 
      saveBlob(data, val.size, val.id, layer.Type, index, info, layer, base, imageType); 
      if (index < maxThreads - 1) { 
       getLayer(++index, info, layer, base, imageType); 
      } else { 
       return; 
      } 
     } 
    }); 
} 

function saveBlob(blob, length, id, layerID, index, info, layer, base, imageType) { 
    if (blob.size != length) { 
     console.error("Blob Length found: ", blob.size, " expected: ", length); 
    } 
    var blobID = layerID + "-" + id; 
    var type = blob.type; 
    DB.putAttachment(blobID + "/pic", blob, type, function (err, response) { 
     if (err) { 
      console.error("Could store blob: error: " + err.error + " reason: " + err.reason + " status: " + err.status); 
     } else { 
      console.log("saved: ", response.id + " rev: " + response.rev); 
      layer.SaveCount++; 
      getLayer(index, info, layer, base, imageType); 
     } 
    }); 
}