【问题标题】:How can I make batches of ajax requests in jQuery?如何在 jQuery 中进行批量 ajax 请求?
【发布时间】:2011-10-22 14:55:44
【问题描述】:

我想知道如何在 n 组中进行 ajax 调用。

这是我的用例:

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

在某些情况下,最多可以同时钻取 50 行。可以想象,这会给服务器带来很大压力。我怎样才能最好地以较小的批次发送这些调用,在它们触发之前等待批次?

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

【问题讨论】:

标签: jquery ajax


【解决方案1】:

使用 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);      
   });
}

【讨论】:

  • 我需要进行 5K xhr2 查询,发送 50 个批次。(Chrome 会在 SPDY 服务器上引发内存故障),Chromium 人员最终会修复,但我现在需要节流。我认为你的递归方法很有希望。
【解决方案2】:

你可以看看使用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 了解更多信息。

另外,我不确定您对使用插件的担忧是否应该受到您处于工作环境中的事实的影响,特别是如果它简化了您的工作。因此可以提高生产力。当然,您必须谨慎选择插件,因为质量和长期维护可能是个问题。

【讨论】:

  • jQuery Deferred object 绝对是处理异步请求的最佳方式。在处理 $.ajax 承诺对象和由 setTimeout 产生的代码时使用 $.when 和 $.done 使我的代码更清晰、更易读。好电话。
  • 是的,理解 $.when() 但对于我的情况来说,使用 5K xhr2 查询看起来很麻烦,每批发送 50 个。(Chrom 使用 SPDY 服务器引发内存故障),Chromium 的人会最终修复,但我现在需要节流。我想我可以尝试下面的递归建议。听起来对吗?
【解决方案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 选项。它只是覆盖它。如果你是,你可以检查它并确保之前的完整函数仍然被调用。

【讨论】:

  • 啊,这太完美了。我会玩弄它,看看我能做什么。我唯一担心的是,this.current 中是否存在竞争条件?我知道很少有 2 个 ajax 调用同时完成,所以值得考虑吗?
  • 没有。浏览器确保两个用户定义的函数不能同时运行。这就是为什么运行无限的while循环会锁定与网页的交互。它也让事情变得更简单。
  • 有任何使用示例的机会吗?
  • @Ben 我对 javascript 很幼稚。你能解释一下如何使用这个函数/对象
【解决方案4】:

调用的递归批处理对我有用。但是因为我得到了 4K 的 XHR2 blob 并将每个 blob 保存在 IndexedDB (PouchDB) 中。我有 XHR2 和 IDB puts 的线程。所以我必须更老练一点:

     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);
        }
    });
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-22
    相关资源
    最近更新 更多