等到所有的jQuery Ajax请求完成?

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

总之,在执行下一步之前,我需要等待所有的Ajax请求完成。 但是,如何?

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

http://api.jquery.com/jQuery.when/

它接受任意数量的Deferred对象作为参数,并在全部parsing时执行一个函数。

这意味着,如果你想发起(例如)四个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, ... }); } 

在我看来,它提供了一个干净清晰的语法,避免了涉及任何全局variables,如ajaxStart和ajaxStop,这些variables可能会在页面开发时产生不必要的副作用。

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

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

如果要等到文档中的所有ajax请求完成,无论它们有多less个,都可以这样使用$.ajaxStop事件:

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

在这种情况下,没有必要猜测将来可能完成的应用程序中有多less个请求。 在某些情况下,ajax请求可能是函数内部逻辑的一部分,这可能相当复杂(例如调用其他函数),在这种情况下,您可能不会等到函数完成了整个逻辑,而只是等待ajax部分来完成。

$.ajaxStop在这里也可以绑定到你认为可能被ajax修改的任何html节点。

这个处理程序的目的是要知道什么时候没有活动的 Ajax不清除或重置某些东西。

我发现了一个很好的答案 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); 

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

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

注:上面的答案使用function,在写这个答案时不存在。 我build议使用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},但你不想locking浏览器,你可以用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(); }); }); 

使用ajaxStop事件。

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

从jQuery 文档 :

 $("#loading").ajaxStop(function() { $(this).hide(); }); 

请注意,它将等待该页面上所有的Ajax请求。

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

例如:

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

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

你可能只需要使用jquery.ajax的成功/完整的方法

或者你可以使用.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)被称为更精确的伪代码。

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

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

希望可以有用…

在@BBififield的答案的基础上,我写了一个实用函数,使信号量逻辑不是在所有的ajax调用传播。

untilAjax是所有ajaxCalls完成时调用callback函数的实用函数。

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

fn是callback函数

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

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

即使这个问题有超过百万的答案,我仍然没有发现任何有用的东西我的情况。 假设你必须处理现有的代码库,已经做了一些Ajax调用,不想引入承诺的复杂性和/或重做整个事情。

我们可以很容易地利用已经成为jQuery一部分的jQuery .data.on.trigger函数。

Codepen

关于我的解决scheme的好东西是:

  • 这显然是callback完全取决于

  • 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> 

如果你需要简单的东西, 一次,完成callback

  //multiple ajax calls above var callback = function () { if ($.active !== 0) { setTimeout(callback, '500'); return; } //whatever you need to do here //... }; callback(); 

我遇到了这个问题,并创build了一个通用的插件jquery_counter来解决它: https ://bitbucket.org/stxnext/jquery_counter/

我find简单的方法,它使用shift()

 function waitReq(id) { jQuery.ajax( { type: 'POST', url: ajaxurl, data: { "page": id }, success: function(resp) { ........... // check array length if not "0" continue to use next array value if(ids.length) { waitReq(ids.shift()); // 2 ) }, error: function(resp) { .................... if(ids.length) { waitReq(ids.shift()); ) } }); } var ids = [1, 2, 3, 4, 5]; // shift() = delete first array value (then print) waitReq(ids.shift()); // print 1 

你也可以使用async.js 。

我认为它比$更好,因为你可以合并各种asynchronous调用,如超时,SqlLite调用等,而不仅仅是ajax请求。

我的解决scheme如下

 var request; ... 'services': { 'GetAddressBookData': function() { //This is the primary service that loads all addressbook records request = $.ajax({ type: "POST", url: "Default.aspx/GetAddressBook", contentType: "application/json;", dataType: "json" }); }, ... 'apps': { 'AddressBook': { 'data': "", 'Start': function() { ...services.GetAddressBookData(); request.done(function(response) { trace("ajax successful"); ..apps.AddressBook.data = response['d']; ...apps.AddressBook.Filter(); }); request.fail(function(xhr, textStatus, errorThrown) { trace("ajax failed - " + errorThrown); }); 

工作很好。 我尝试了很多不同的方式来做这件事,但我发现这是最简单,最可重用的。 希望它有帮助

看看我的解决scheme:

1.将这个函数(和variables)插入到你的javascript文件中:

 var runFunctionQueue_callback; function runFunctionQueue(f, index, callback) { var next_index = index + 1 if (callback !== undefined) runFunctionQueue_callback = callback; if (f[next_index] !== undefined) { console.log(index + ' Next function avalaible -> ' + next_index); $.ajax({ type: 'GET', url: f[index].file, data: (f[index].data), complete: function() { runFunctionQueue(f, next_index); } }); } else { console.log(index + ' Last function'); $.ajax({ type: 'GET', url: f[index].file, data: (f[index].data), async: false, complete: runFunctionQueue_callback }); } } 

2.用你的请求build立一个数组,像这样:

 var f = [ {file: 'file_path', data: {action: 'action', data: 'any_data}}, {file: 'file_path', data: {action: 'action', data: 'any_data}}, {file: 'file_path', data: {action: 'action', data: 'any_data}}, {file: 'file_path', data: {action: 'action', data: 'any_data}} ]; 

3.创buildcallback函数:

 function Function_callback() { alert('done'); } 

4.使用参数调用runFunctionQueue函数:

 runFunctionQueue(f, 0, QuestionInsert_callback); // first parameter: array with requests data // second parameter: start from first request // third parameter: the callback function 

Alex给出的解决scheme工作正常。 相同的概念,但使用一点点不同的方式(当电话的数量是未知的提前)

http://garbageoverflow.blogspot.com/2014/02/wait-for-n-or-multiple-or-unknown.html

试试这个方法。 在java脚本函数内部build立一个循环,等到ajax调用完成。

 function getLabelById(id) { var label = ''; var done = false; $.ajax({ cache: false, url: "YourMvcActionUrl", type: "GET", dataType: "json", async: false, error: function (result) { label='undefined'; done = true; }, success: function (result) { label = result.Message; done = true; } }); //A loop to check done if ajax call is done. while (!done) { setTimeout(function(){ },500); // take a sleep. } return label; }