我如何让一个函数等待,直到所有的jQuery Ajax请求在另一个函数内完成?

简而言之,在执行下一个Ajax请求之前,我需要等待所有Ajax请求都完成。但如何?


当前回答

如果您想知道文档中所有ajax请求何时完成,无论它们有多少,只需使用$。ajaxStop事件如下所示:

$(document).ajaxStop(function () {
  // 0 === $.active
});

在这种情况下,您既不需要猜测应用程序中发生了多少请求(这些请求可能在将来完成),也不需要深入研究函数的复杂逻辑或查找哪些函数正在执行HTTP(S)请求。 美元。这里的ajaxStop也可以绑定到任何HTML节点 认为可以按要求修改。


更新: 如果您想坚持使用ES语法,那么可以使用Promise。所有已知的ajax方法:

Promise.all([ajax1(), ajax2()]).then(() => {
  // all requests finished successfully
}).catch(() => {
  // all requests finished but one or more failed
})

这里有趣的一点是,它同时适用于Promises和$。ajax请求。

下面是jsFiddle演示。


更新2: 使用async/await语法的最新版本:

try {
  const results = await Promise.all([ajax1(), ajax2()])
  // do other actions
} catch(ex) { }

其他回答

注意:上面的答案使用的功能在编写这个答案时并不存在。我建议使用jQuery.when()而不是这些方法,但我把答案留给历史用途。

-

您可能可以使用一个简单的计数信号量,尽管如何实现它取决于您的代码。一个简单的例子是……

var semaphore  = 0,     // counting semaphore for ajax requests
    all_queued = false; // bool indicator to account for instances where the first request might finish before the second even starts

semaphore++;
$.get('ajax/test1.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // process your custom stuff here
    }
});

semaphore++;
$.get('ajax/test2.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // process your custom stuff here
    }
});

semaphore++;
$.get('ajax/test3.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // process your custom stuff here
    }
});

semaphore++;
$.get('ajax/test4.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // process your custom stuff here
    }
});

// now that all ajax requests are queued up, switch the bool to indicate it
all_queued = true;

如果你想让它像{async: false}一样操作,但又不想锁定浏览器,你可以用jQuery队列来完成同样的事情。

var $queue = $("<div/>");
$queue.queue(function(){
    $.get('ajax/test1.html', function(data) {
        $queue.dequeue();
    });
}).queue(function(){
    $.get('ajax/test2.html', function(data) {
        $queue.dequeue();
    });
}).queue(function(){
    $.get('ajax/test3.html', function(data) {
        $queue.dequeue();
    });
}).queue(function(){
    $.get('ajax/test4.html', function(data) {
        $queue.dequeue();
    });
});

jQuery现在为此定义了一个when函数。

它接受任意数量的Deferred对象作为参数,并在所有这些对象都解析时执行函数。

这意味着,如果你想发起(例如)四个ajax请求,然后在它们完成时执行一个动作,你可以这样做:

$.when(ajax1(), ajax2(), ajax3(), ajax4()).done(function(a1, a2, a3, a4){
    // the code here will be executed when all four ajax requests resolve.
    // a1, a2, a3 and a4 are lists of length 3 containing the response text,
    // status, and jqXHR object for each of the four ajax calls respectively.
});

function ajax1() {
    // NOTE:  This function must return the value 
    //        from calling the $.ajax() method.
    return $.ajax({
        url: "someUrl",
        dataType: "json",
        data:  yourJsonData,            
        ...
    });
}

在我看来,这使得语法干净明了,并且避免涉及任何全局变量,如ajaxStart和ajaxStop,这可能会在页面开发过程中产生不必要的副作用。

如果你事先不知道你需要等待多少个ajax参数(即你想使用可变数量的参数),它仍然可以完成,只是有点棘手。参见在一个数组中传递deferred to $.when()(也可以是jQuery .当使用可变参数进行故障排除时)。

如果你需要更深入地控制ajax脚本的失败模式等,你可以保存.when()返回的对象-它是一个包含所有原始ajax查询的jQuery承诺对象。您可以调用.then()或.fail()来添加详细的成功/失败处理程序。

当所有ajax加载完成时,我使用大小检查

function get_ajax(link, data, callback) { $.ajax({ url: link, type: "GET", data: data, dataType: "json", success: function (data, status, jqXHR) { callback(jqXHR.status, data) }, error: function (jqXHR, status, err) { callback(jqXHR.status, jqXHR); }, complete: function (jqXHR, status) { } }) } function run_list_ajax(callback){ var size=0; var max= 10; for (let index = 0; index < max; index++) { var link = 'http://api.jquery.com/ajaxStop/'; var data={i:index} get_ajax(link,data,function(status, data){ console.log(index) if(size>max-2){ callback('done') } size++ }) } } run_list_ajax(function(info){ console.log(info) }) <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>

在@BBonifield回答的基础上,我写了一个实用函数,这样信号量逻辑就不会分布在所有ajax调用中。

untilAjax是一个实用函数,它在所有ajaxCalls完成后调用回调函数。

ajaxObjs是一个ajax设置对象的数组[http://api.jquery.com/jQuery.ajax/]。

Fn是回调函数

function untilAjax(ajaxObjs, fn) {
  if (!ajaxObjs || !fn) {
    return;
  }
  var ajaxCount = ajaxObjs.length,
    succ = null;

  for (var i = 0; i < ajaxObjs.length; i++) { //append logic to invoke callback function once all the ajax calls are completed, in success handler.
    succ = ajaxObjs[i]['success'];
    ajaxObjs[i]['success'] = function(data) { //modified success handler
      if (succ) {
        succ(data);
      }
      ajaxCount--;
      if (ajaxCount == 0) {
        fn(); //modify statement suitably if you want 'this' keyword to refer to another object
      }
    };
    $.ajax(ajaxObjs[i]); //make ajax call
    succ = null;
  };

示例:doSomething函数使用untilAjax。

function doSomething() {
  // variable declarations
  untilAjax([{
    url: 'url2',
    dataType: 'json',
    success: function(data) {
      //do something with success data
    }
  }, {
    url: 'url1',
    dataType: 'json',
    success: function(data) {
      //do something with success data
    }
  }, {
    url: 'url2',
    dataType: 'json',
    success: function(response) {
      //do something with success data
    }
  }], function() {
    // logic after all the calls are completed.
  });
}

jQuery允许您指定是否希望ajax请求是异步的。您可以简单地使ajax请求同步,然后其余的代码直到它们返回才执行。

例如:

jQuery.ajax({ 
    async: false,
    //code
});