等到所有jQuery Ajax请求都完成了?

jam*_*lin 644 javascript ajax jquery

如何使函数等到所有jQuery Ajax请求在另一个函数内完成?

简而言之,我需要等待所有Ajax请求在执行下一个之前完成.但是怎么样?

Ale*_*lex 875

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,            
        ...
    });
}
Run Code Online (Sandbox Code Playgroud)

在我看来,它使得语法清晰明确,并避免涉及任何全局变量,如ajaxStart和ajaxStop,这些变量可能会在页面开发时产生不必要的副作用.

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

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

  • 这应该被标记为正确答案,因为它简单,高效且效果​​很好.此外,应该注意`$ .when`返回一个`Promise`对象,它有更多有用的方法,而不仅仅是`.done`.例如,使用`.then(onSuccess,onFailure)`方法,您可以在两个请求成功或至少其中一个失败时做出反应. (44认同)
  • 小心`fail`案例.与`done`不同,`fail`会在第一次失败时立即触发,并忽略剩余的延迟. (32认同)
  • 是否可以将请求ajax1..4捆扎成一个数组并将其传递? (2认同)
  • 让人们接触到 when 方法和一般的 Promise 是很棒的,但我认为这不是最好的答案。如果任何一个 ajax 函数在任何地方创建另一个 ajax 请求,然后不将该新的承诺正确地集成到链中......这些请求将逃脱这种技术。例如,如果不修改用于 ajax 添加到购物车行为的 Shopify 库,我就无法使用此技术,因为它不是以“promisy”方式编写的,并且永远不会返回它创建的 xhr 对象。这有道理吗?不过,这仍然是一个很好的答案! (2认同)
  • 当请求失败时不起作用。投反对票。答案完成后将投票。这意味着,我只想在所有请求(包括失败的请求)完成后才继续。 (2认同)

Ars*_*yan 282

如果您想等到文档中的所有ajax请求都完成,无论它们有多少,只需以$.ajaxStop这种方式使用事件:

  $(document).ajaxStop(function () {
      // 0 === $.active
  });
Run Code Online (Sandbox Code Playgroud)

在这种情况下,无需猜测将来可能完成的应用程序中有多少请求.在某些情况下,ajax请求可以是函数内部逻辑的一部分,这可能非常复杂(例如调用其他函数),在这种情况下,您可能不会等到所述函数完成其整个逻辑而不是等待ajax部分完成.

$.ajaxStop这里也可以绑定到HTML您认为可能被修改的任何节点ajax.

同样,此处理程序的目的是知道何时没有活动 ajax不清除或重置某些内容.

PS如果您不介意使用ES6语法,则可以使用Promise.all已知ajax方法.例:

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

这里有一个有趣的一点是,它的作品都与Promises$.ajax请求.这是jsFiddle演示的最后一个.

  • +1比其他答案好得多***如果***你必须处理带有匿名回调/闭包的第三方脚本. (14认同)
  • 与when()解决方案相比,即使ajax调用的数量未知,它也具有工作的优势. (6认同)
  • @kaiser有效点,但不是问题的问题.如果您不想等待所有AJAX调用返回,那就不太好了.问题是关于等待你自己做的AJAX调用(在OP写的内部调用另一个函数).其他一些代码可能已经进行了另一个您不想等待的AJAX调用. (5认同)
  • 与when()解决方案相比,它具有很大的缺点,即不能与其他组件一起很好地工作,因为它共享文档范围的全局状态.如果持续进行一些长时间的轮询,它甚至可能永远不会开火. (5认同)
  • 你是不正确的@AdrienBe,ajaxStop处理所有的ajax请求,无论它们是否成功,就像我的文字的证据一样看http://jsfiddle.net/36votxba/2/ (3认同)
  • 你是完全正确的,谢谢你纠正我 (2认同)

jam*_*lin 31

我发现了一个很好的答案gnarf我的自我,这正是我一直在寻找:)

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);
Run Code Online (Sandbox Code Playgroud)

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

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

  • 看起来你忘了给[这个答案]正确归属(http://stackoverflow.com/questions/3034874/sequencing-ajax-requests/3035268#3035268),我已经添加了它. (37认同)

BBo*_*eld 20

注意:上述答案使用的是撰写本答案时不存在的功能.我建议使用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;
Run Code Online (Sandbox Code Playgroud)

如果您希望它像{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();
    });
});
Run Code Online (Sandbox Code Playgroud)

  • 这似乎会使一个微不足道的问题过于复杂化. (10认同)
  • 这真的不是那么复杂.计数信号量是CS中的常见机制.如果您愿意,使用jQuery队列的示例也可以正常工作,而无需自己实现信号量. (2认同)
  • 嗯......我不是给你-1的人......我知道答案确实会变老。然而,人们一直在寻找它们,据我所知,不禁止向今天仍有可能使用它们的人提供信息。 (2认同)

ola*_*ure 20

使用该ajaxStop活动.

例如,假设您在获取100个ajax请求时有一个loading ...消息,并且您希望在加载后隐藏该消息.

来自jQuery doc:

$("#loading").ajaxStop(function() {
  $(this).hide();
});
Run Code Online (Sandbox Code Playgroud)

请注意,它将等待在该页面上完成的所有ajax请求.

  • 这假设您知道页面上不会有任何其他AJAX请求,这不是一个很好的假设 (5认同)
  • 我认为,这是迄今为止最好的解决方案......干杯 (2认同)

shm*_*613 7

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

例如:

jQuery.ajax({ 
    async: false,
    //code
});
Run Code Online (Sandbox Code Playgroud)

  • 需要注意的一点是,使用 { async: false } 可以暂时锁定浏览器。http://api.jquery.com/jQuery.ajax/ (44认同)
  • 这是非常糟糕的主意!*永远不要*这样做!阻塞 = 根本不响应用户操作,甚至不响应滚动或任何操作!(此外, async: false 将在 jQuery 1.8 中被弃用。) (44认同)
  • 这与标准的 jQuery/Javascript 实践背道而驰。AJAX 总是应该是异步的。你应该使用 jQuery.when() 代替。 (31认同)
  • 这是一个非常糟糕的主意。不要使用这个答案。 (27认同)
  • 特别是如果请求失败或由于某些不可预测的原因需要很长时间(根据墨菲定律,这肯定会发生!),由于如上所述的浏览器锁定,这对于生产代码通常是一个坏主意。 (5认同)
  • 作为网站管理员,是否给我的用户带来潜在的糟糕体验是我的决定。社区对我的网站一无所知,那么他们如何判断我的网站如何运作?弃用 async: false 对任何真正需要它的人来说都是一记耳光。 (4认同)
  • 不幸的是,他们从 1.8 中删除了 { async : false } ,这真的很糟糕。有时您只需要使用可选超时阻塞调用。 (3认同)
  • 确切地!这样您就知道在调用所有 ajax 请求的函数结束时,它们都已完成执行。 (2认同)

Ste*_*ano 7

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...
  }
});
Run Code Online (Sandbox Code Playgroud)

虽然你应该发布一个关于你的ajax请求如何被称为更准确的伪代码...


Jes*_*fre 7

一个小的解决方法是这样的:

// Define how many Ajax calls must be done
var ajaxCalls = 3;
var counter = 0;
var ajaxCallComplete = function() {
    counter++;
    if( counter >= ajaxCalls ) {
            // When all ajax calls has been done
        // Do something like hide waiting images, or any else function call
        $('*').css('cursor', 'auto');
    }
};

var loadPersons = function() {
        // Show waiting image, or something else
    $('*').css('cursor', 'wait');

    var url = global.ctx + '/loadPersons';
    $.getJSON(url, function(data) {
            // Fun things
    })
    .complete(function() { **ajaxCallComplete();** });
};

var loadCountries = function() {
    // Do things
    var url = global.ctx + '/loadCountries';
    $.getJSON(url, function(data) {
            // Travels
    })
    .complete(function() { **ajaxCallComplete();** });
};

var loadCities = function() {
    // Do things
    var url = global.ctx + '/loadCities';
    $.getJSON(url, function(data) {
            // Travels
    })
    .complete(function() { **ajaxCallComplete();** });
};

$(document).ready(function(){
    loadPersons();
    loadCountries();
    loadCities();
});
Run Code Online (Sandbox Code Playgroud)

希望可能有用......