我如何让一个函数等待,直到所有的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) { }

其他回答

为了扩展Alex的回答,我举了一个带有可变论点和承诺的例子。我想通过ajax加载图像,并在它们全部加载后显示在页面上。

为了做到这一点,我使用了以下方法:

let urlCreator = window.URL || window.webkitURL;

// Helper function for making ajax requests
let fetch = function(url) {
    return $.ajax({
        type: "get",
        xhrFields: {
            responseType: "blob"
        },
        url: url,
    });
};

// Map the array of urls to an array of ajax requests
let urls = ["https://placekitten.com/200/250", "https://placekitten.com/300/250"];
let files = urls.map(url => fetch(url));

// Use the spread operator to wait for all requests
$.when(...files).then(function() {
    // If we have multiple urls, then loop through
    if(urls.length > 1) {
        // Create image urls and tags for each result
        Array.from(arguments).forEach(data => {
            let imageUrl = urlCreator.createObjectURL(data[0]);
            let img = `<img src=${imageUrl}>`;
            $("#image_container").append(img);
        });
    }
    else {
        // Create image source and tag for result
        let imageUrl = urlCreator.createObjectURL(arguments[0]);
        let img = `<img src=${imageUrl}>`;
        $("#image_container").append(img);
    }
});

更新工作的单个或多个url: https://jsfiddle.net/euypj5w9/

Javascript是基于事件的,所以你不应该等待,而应该设置钩子/回调

你可以只使用jquery.ajax的success/complete方法

或者你可以使用。ajaxcomplete:

$('.log').ajaxComplete(function(e, xhr, settings) {
  if (settings.url == 'ajax/test.html') {
    $(this).text('Triggered ajaxComplete handler.');
    //and you can do whatever other processing here, including calling another function...
  }
});

虽然你应该张贴一个伪代码你的(s) ajax请求(s)是(是)被调用更精确…

如果从头开始,我强烈建议使用$.when()。

尽管这个问题有超过一百万个答案,但我仍然没有找到任何对我的情况有用的答案。假设您必须处理现有的代码库,已经进行了一些ajax调用,并且不想引入承诺的复杂性和/或重做整个事情。

我们可以很容易地利用jQuery的.data, .on和.trigger函数,这些函数一直是jQuery的一部分。

Codepen

我的解决方案的优点是:

显然回调依赖于什么 函数triggerNowOrOnLoaded并不关心数据是否已经加载或我们仍在等待它 将其插入现有代码非常容易

$(function() { // wait for posts to be loaded triggerNowOrOnLoaded("posts", function() { var $body = $("body"); var posts = $body.data("posts"); $body.append("<div>Posts: " + posts.length + "</div>"); }); // some ajax requests $.getJSON("https://jsonplaceholder.typicode.com/posts", function(data) { $("body").data("posts", data).trigger("posts"); }); // doesn't matter if the `triggerNowOrOnLoaded` is called after or before the actual requests $.getJSON("https://jsonplaceholder.typicode.com/users", function(data) { $("body").data("users", data).trigger("users"); }); // wait for both types triggerNowOrOnLoaded(["posts", "users"], function() { var $body = $("body"); var posts = $body.data("posts"); var users = $body.data("users"); $body.append("<div>Posts: " + posts.length + " and Users: " + users.length + "</div>"); }); // works even if everything has already loaded! setTimeout(function() { // triggers immediately since users have been already loaded triggerNowOrOnLoaded("users", function() { var $body = $("body"); var users = $body.data("users"); $body.append("<div>Delayed Users: " + users.length + "</div>"); }); }, 2000); // 2 seconds }); // helper function function triggerNowOrOnLoaded(types, callback) { types = $.isArray(types) ? types : [types]; var $body = $("body"); var waitForTypes = []; $.each(types, function(i, type) { if (typeof $body.data(type) === 'undefined') { waitForTypes.push(type); } }); var isDataReady = waitForTypes.length === 0; if (isDataReady) { callback(); return; } // wait for the last type and run this function again for the rest of the types var waitFor = waitForTypes.pop(); $body.on(waitFor, function() { // remove event handler - we only want the stuff triggered once $body.off(waitFor); triggerNowOrOnLoaded(waitForTypes, callback); }); } <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <body>Hi!</body>

我找到了一个很好的答案,这正是我在寻找的:)

jQuery ajaxQueue

//This handles the queues    
(function($) {

  var ajaxQueue = $({});

  $.ajaxQueue = function(ajaxOpts) {

    var oldComplete = ajaxOpts.complete;

    ajaxQueue.queue(function(next) {

      ajaxOpts.complete = function() {
        if (oldComplete) oldComplete.apply(this, arguments);

        next();
      };

      $.ajax(ajaxOpts);
    });
  };

})(jQuery);

然后你可以像这样向队列添加一个ajax请求:

$.ajaxQueue({
        url: 'page.php',
        data: {id: 1},
        type: 'POST',
        success: function(data) {
            $('#status').html(data);
        }
    });

美元。当不为我工作时,回调(x)而不是返回x工作如下所述:https://stackoverflow.com/a/13455253/10357604