等待所有jQuery Ajax请求完成?

时间:2021-07-13 04:23:31

How do I make a function wait until all jQuery Ajax requests are done inside another function?

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

In short, I need to wait for all Ajax requests to be done before I execute the next. But how?

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

18 个解决方案

#1


735  

jQuery now defines a when function for this purpose.

jQuery现在为这个目的定义了一个函数。

It accepts any number of Deferred objects as arguments, and executes a function when all of them resolve.

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

That means, if you want to initiate (for example) four ajax requests, then perform an action when they are done, you could do something like this:

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

In my opinion, it makes for a clean and clear syntax, and avoids involving any global variables such as ajaxStart and ajaxStop, which could have unwanted side effects as your page develops.

在我看来,它是一种简洁明了的语法,避免涉及任何全局变量,如ajaxStart和ajaxStop,随着页面的发展,这些变量可能会产生不必要的副作用。

If you don't know in advance how many ajax arguments you need to wait for (i.e. you want to use a variable number of arguments), it can still be done but is just a little bit trickier. See Pass in an array of Deferreds to $.when() (and maybe jQuery .when troubleshooting with variable number of arguments).

如果您事先不知道需要等待多少ajax参数(也就是说,您希望使用可变数量的参数),它仍然可以完成,但只是稍微复杂一点。查看传递给$ when(和可能是jQuery)的递归数组。

If you need deeper control over the failure modes of the ajax scripts etc., you can save the object returned by .when() - it's a jQuery Promise object encompassing all of the original ajax queries. You can call .then() or .fail() on it to add detailed success/failure handlers.

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

#2


240  

If you want to wait until all ajax requests are finished in your document, no matter how many of them exist, just use $.ajaxStop event this way:

如果您想要等到所有ajax请求都在文档中完成,不管它们有多少,只需使用$。ajaxStop事件:

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

In this case, there is no need to guess how many requests can be in an application that might finish in the future. In some cases ajax requests can be part of a function's inner logic, which can be quite complicated (e.g. calling other functions), and in that case, you might not wait until said function is done with its entire logic rather than only waiting for the ajax part to complete.

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

$.ajaxStop here can also be bound to any HTML node that you think might be modified by ajax.

美元。这里的ajaxStop还可以绑定到任何您认为可能被ajax修改过的HTML节点。

Again the purpose of this handler is to know when there is no active ajax not to clear or reset something.

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

P.S. If you don't mind using ES6 syntax, then you can use Promise.all for known ajax methods. Example:

如果您不介意使用ES6语法,那么您可以使用Promise。所有已知的ajax方法。例子:

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

An interesting point here is that works both with Promises and $.ajax requests. Here is jsFiddle demonstrating the last one.

这里有一个有趣的地方,那就是承诺和$。ajax请求。这是jsFiddle展示的最后一个。

#3


28  

I found a good answer by gnarf my self which is exactly what I was looking for :)

我通过gnarf找到了一个很好的答案,这正是我想要的:)

jQuery ajaxQueue

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

Then you can add a ajax request to the queue like this:

然后可以将ajax请求添加到队列中:

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

#4


20  

NOTE: The above answers use functionality that didn't exist at the time that this answer was written. I recommend using jQuery.when() instead of these approaches, but I'm leaving the answer for historical purposes.

注意:上面的答案使用的功能在这个答案写的时候并不存在。我建议使用jQuery.when()而不是这些方法,但是出于历史原因,我将保留这个答案。

-

- - - - - -

You could probably get by with a simple counting semaphore, although how you implement it would be dependent on your code. A simple example would be something like...

您可能会通过一个简单的计数信号量来获得,尽管您如何实现它将取决于您的代码。一个简单的例子是……

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;

If you wanted this to operate like {async: false} but you didn't want to lock the browser, you could accomplish the same thing with a jQuery queue.

如果你想让它像{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();
    });
});

#5


19  

Use the ajaxStop event.

使用ajaxStop事件。

For example, let's say you have a loading ... message while fetching 100 ajax requests and you want to hide that message once loaded.

例如,假设您有一个加载…在获取100个ajax请求时,您想要隐藏这个消息。

From the jQuery doc:

从jQuery文档:

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

Do note that it will wait for all ajax requests being done on that page.

请注意,它将等待在该页面上执行的所有ajax请求。

#6


7  

A little workaround is something like this:

一个小小的变通方法是这样的:

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

Hope can be useful...

希望可以有用……

#7


6  

javascript is event-based, so you should never wait, rather set hooks/callbacks

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

You can probably just use the success/complete methods of jquery.ajax

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

Or you could use .ajaxComplete :

或者你可以用。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...
  }
});

though youy should post a pseudocode of how your(s) ajax request(s) is(are) called to be more precise...

虽然你应该发布一个伪代码,说明你的(s) ajax请求是如何被调用的更精确……

#8


3  

jQuery allows you to specify if you want the ajax request to be asynchronous or not. You can simply make the ajax requests synchronous and then the rest of the code won't execute until they return.

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

For example:

例如:

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

#9


1  

On the basis of @BBonifield answer, I wrote a utility function so that semaphore logic is not spread in all the ajax calls.

在@BBonifield答案的基础上,我编写了一个实用程序函数,以便在所有ajax调用中都不会传播信号量逻辑。

untilAjax is the utility function which invokes a callback function when all the ajaxCalls are completed.

untilAjax是在所有ajax调用完成时调用回调函数的实用函数。

ajaxObjs is a array of ajax setting objects [http://api.jquery.com/jQuery.ajax/].

ajaxObjs是一组ajax设置对象。

fn is callback function

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

Example: doSomething function uses untilAjax.

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

#10


1  

I highly recommend using $.when() if you're starting from scratch.

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

Even though this question has over million answers, I still didn't find anything useful for my case. Let's say you have to deal with an existing codebase, already making some ajax calls and don't want to introduce the complexity of promises and/or redo the whole thing.

即使这个问题有超过百万的答案,我仍然没有发现任何对我的情况有用的东西。假设您必须处理一个现有的代码库,已经在进行一些ajax调用,并且不想引入承诺的复杂性,或者重做整件事情。

We can easily take advantage of jQuery .data, .on and .trigger functions which have been a part of jQuery since forever.

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

Codepen

Codepen

The good stuff about my solution is:

我的解决方案的优点是:

  • it's obvious what the callback exactly depends on

    很明显,这个回调具体取决于什么。

  • the function triggerNowOrOnLoaded doesn't care if the data has been already loaded or we're still waiting for it

    triggernoworonload函数并不关心数据是否已经加载,或者我们还在等待它。

  • it's super easy to plug it into an existing code

    将其插入到现有代码中非常容易。

$(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>

#11


0  

If you need something simple; once and done callback

如果你需要一些简单的东西;一次,做回调

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

#12


0  

I have met this problem and created a generic plugin jquery_counter to solve it: https://bitbucket.org/stxnext/jquery_counter/

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

#13


0  

I found simple way, it using shift()

我找到了简单的方法,它使用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

#14


0  

Also you could use async.js.

还可以使用async.js。

I think its better than $.when because you can merge all kinds of asynchronous call that does not support promises out of the box like timeouts, SqlLite calls etc. and not just ajax requests.

我认为它比美元好。因为您可以合并所有不支持的异步调用,比如超时、SqlLite调用等等,而不仅仅是ajax请求。

#15


0  

My solution is as follows

我的解决方案如下。

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

Worked quite nicely. I've tried a lot of different ways of doing this, but I found this to be the simplest and most reusable. Hope it helps

很好地工作。我尝试了很多不同的方法,但我发现这是最简单也是最可重用的。希望它能帮助

#16


0  

Look at my solution:

看我的解决方案:

1.Insert this function (and variable) into your javascript file:

1。将这个函数(和变量)插入到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.Buil an array with your requests, like this:

2。将一个数组与您的请求,如下所示:

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.Create callback function:

3所示。创建回调函数:

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

4.Call the runFunctionQueue function with parameters:

4所示。使用参数调用runFunctionQueue函数:

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

#17


-1  

Solution given by Alex works fine. Same concept but using it a little different way (when number of calls is not known in advance)

Alex给出的解决方案很好。相同的概念,但使用的方式略有不同(当调用的数量事先不知道的时候)

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

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

#18


-4  

Try this way. make a loop inside java script function to wait until the ajax call finished.

尝试这种方式。在java脚本函数中创建一个循环,等待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;
}

#1


735  

jQuery now defines a when function for this purpose.

jQuery现在为这个目的定义了一个函数。

It accepts any number of Deferred objects as arguments, and executes a function when all of them resolve.

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

That means, if you want to initiate (for example) four ajax requests, then perform an action when they are done, you could do something like this:

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

In my opinion, it makes for a clean and clear syntax, and avoids involving any global variables such as ajaxStart and ajaxStop, which could have unwanted side effects as your page develops.

在我看来,它是一种简洁明了的语法,避免涉及任何全局变量,如ajaxStart和ajaxStop,随着页面的发展,这些变量可能会产生不必要的副作用。

If you don't know in advance how many ajax arguments you need to wait for (i.e. you want to use a variable number of arguments), it can still be done but is just a little bit trickier. See Pass in an array of Deferreds to $.when() (and maybe jQuery .when troubleshooting with variable number of arguments).

如果您事先不知道需要等待多少ajax参数(也就是说,您希望使用可变数量的参数),它仍然可以完成,但只是稍微复杂一点。查看传递给$ when(和可能是jQuery)的递归数组。

If you need deeper control over the failure modes of the ajax scripts etc., you can save the object returned by .when() - it's a jQuery Promise object encompassing all of the original ajax queries. You can call .then() or .fail() on it to add detailed success/failure handlers.

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

#2


240  

If you want to wait until all ajax requests are finished in your document, no matter how many of them exist, just use $.ajaxStop event this way:

如果您想要等到所有ajax请求都在文档中完成,不管它们有多少,只需使用$。ajaxStop事件:

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

In this case, there is no need to guess how many requests can be in an application that might finish in the future. In some cases ajax requests can be part of a function's inner logic, which can be quite complicated (e.g. calling other functions), and in that case, you might not wait until said function is done with its entire logic rather than only waiting for the ajax part to complete.

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

$.ajaxStop here can also be bound to any HTML node that you think might be modified by ajax.

美元。这里的ajaxStop还可以绑定到任何您认为可能被ajax修改过的HTML节点。

Again the purpose of this handler is to know when there is no active ajax not to clear or reset something.

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

P.S. If you don't mind using ES6 syntax, then you can use Promise.all for known ajax methods. Example:

如果您不介意使用ES6语法,那么您可以使用Promise。所有已知的ajax方法。例子:

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

An interesting point here is that works both with Promises and $.ajax requests. Here is jsFiddle demonstrating the last one.

这里有一个有趣的地方,那就是承诺和$。ajax请求。这是jsFiddle展示的最后一个。

#3


28  

I found a good answer by gnarf my self which is exactly what I was looking for :)

我通过gnarf找到了一个很好的答案,这正是我想要的:)

jQuery ajaxQueue

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

Then you can add a ajax request to the queue like this:

然后可以将ajax请求添加到队列中:

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

#4


20  

NOTE: The above answers use functionality that didn't exist at the time that this answer was written. I recommend using jQuery.when() instead of these approaches, but I'm leaving the answer for historical purposes.

注意:上面的答案使用的功能在这个答案写的时候并不存在。我建议使用jQuery.when()而不是这些方法,但是出于历史原因,我将保留这个答案。

-

- - - - - -

You could probably get by with a simple counting semaphore, although how you implement it would be dependent on your code. A simple example would be something like...

您可能会通过一个简单的计数信号量来获得,尽管您如何实现它将取决于您的代码。一个简单的例子是……

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;

If you wanted this to operate like {async: false} but you didn't want to lock the browser, you could accomplish the same thing with a jQuery queue.

如果你想让它像{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();
    });
});

#5


19  

Use the ajaxStop event.

使用ajaxStop事件。

For example, let's say you have a loading ... message while fetching 100 ajax requests and you want to hide that message once loaded.

例如,假设您有一个加载…在获取100个ajax请求时,您想要隐藏这个消息。

From the jQuery doc:

从jQuery文档:

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

Do note that it will wait for all ajax requests being done on that page.

请注意,它将等待在该页面上执行的所有ajax请求。

#6


7  

A little workaround is something like this:

一个小小的变通方法是这样的:

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

Hope can be useful...

希望可以有用……

#7


6  

javascript is event-based, so you should never wait, rather set hooks/callbacks

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

You can probably just use the success/complete methods of jquery.ajax

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

Or you could use .ajaxComplete :

或者你可以用。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...
  }
});

though youy should post a pseudocode of how your(s) ajax request(s) is(are) called to be more precise...

虽然你应该发布一个伪代码,说明你的(s) ajax请求是如何被调用的更精确……

#8


3  

jQuery allows you to specify if you want the ajax request to be asynchronous or not. You can simply make the ajax requests synchronous and then the rest of the code won't execute until they return.

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

For example:

例如:

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

#9


1  

On the basis of @BBonifield answer, I wrote a utility function so that semaphore logic is not spread in all the ajax calls.

在@BBonifield答案的基础上,我编写了一个实用程序函数,以便在所有ajax调用中都不会传播信号量逻辑。

untilAjax is the utility function which invokes a callback function when all the ajaxCalls are completed.

untilAjax是在所有ajax调用完成时调用回调函数的实用函数。

ajaxObjs is a array of ajax setting objects [http://api.jquery.com/jQuery.ajax/].

ajaxObjs是一组ajax设置对象。

fn is callback function

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

Example: doSomething function uses untilAjax.

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

#10


1  

I highly recommend using $.when() if you're starting from scratch.

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

Even though this question has over million answers, I still didn't find anything useful for my case. Let's say you have to deal with an existing codebase, already making some ajax calls and don't want to introduce the complexity of promises and/or redo the whole thing.

即使这个问题有超过百万的答案,我仍然没有发现任何对我的情况有用的东西。假设您必须处理一个现有的代码库,已经在进行一些ajax调用,并且不想引入承诺的复杂性,或者重做整件事情。

We can easily take advantage of jQuery .data, .on and .trigger functions which have been a part of jQuery since forever.

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

Codepen

Codepen

The good stuff about my solution is:

我的解决方案的优点是:

  • it's obvious what the callback exactly depends on

    很明显,这个回调具体取决于什么。

  • the function triggerNowOrOnLoaded doesn't care if the data has been already loaded or we're still waiting for it

    triggernoworonload函数并不关心数据是否已经加载,或者我们还在等待它。

  • it's super easy to plug it into an existing code

    将其插入到现有代码中非常容易。

$(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>

#11


0  

If you need something simple; once and done callback

如果你需要一些简单的东西;一次,做回调

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

#12


0  

I have met this problem and created a generic plugin jquery_counter to solve it: https://bitbucket.org/stxnext/jquery_counter/

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

#13


0  

I found simple way, it using shift()

我找到了简单的方法,它使用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

#14


0  

Also you could use async.js.

还可以使用async.js。

I think its better than $.when because you can merge all kinds of asynchronous call that does not support promises out of the box like timeouts, SqlLite calls etc. and not just ajax requests.

我认为它比美元好。因为您可以合并所有不支持的异步调用,比如超时、SqlLite调用等等,而不仅仅是ajax请求。

#15


0  

My solution is as follows

我的解决方案如下。

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

Worked quite nicely. I've tried a lot of different ways of doing this, but I found this to be the simplest and most reusable. Hope it helps

很好地工作。我尝试了很多不同的方法,但我发现这是最简单也是最可重用的。希望它能帮助

#16


0  

Look at my solution:

看我的解决方案:

1.Insert this function (and variable) into your javascript file:

1。将这个函数(和变量)插入到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.Buil an array with your requests, like this:

2。将一个数组与您的请求,如下所示:

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.Create callback function:

3所示。创建回调函数:

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

4.Call the runFunctionQueue function with parameters:

4所示。使用参数调用runFunctionQueue函数:

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

#17


-1  

Solution given by Alex works fine. Same concept but using it a little different way (when number of calls is not known in advance)

Alex给出的解决方案很好。相同的概念,但使用的方式略有不同(当调用的数量事先不知道的时候)

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

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

#18


-4  

Try this way. make a loop inside java script function to wait until the ajax call finished.

尝试这种方式。在java脚本函数中创建一个循环,等待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;
}