Подождите, пока все запросы JQuery Ajax не будут выполнены?

Как сделать функцию до тех пор, пока все запросы jQuery Ajax не будут выполнены внутри другой функции?

Короче говоря, мне нужно дождаться, пока все запросы Ajax будут выполнены до того, как я буду выполнять следующий. Но как?

jQuery теперь определяет функцию when для этой цели.

Он принимает любое количество отложенных объектов в качестве аргументов и выполняет функцию, когда все они разрешаются.

Это означает, что если вы хотите инициировать (например) четыре запроса 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 вам нужно подождать (т. Е. Вы хотите использовать переменное количество аргументов), это все равно можно сделать, но это немного сложнее. См. « Передать» в массиве «Отложенные» до $ .when () (и, возможно, jQuery. При устранении неполадок с переменным числом аргументов ).

Если вам нужен более глубокий контроль над режимами сбоя сценариев ajax и т. Д., Вы можете сохранить объект, возвращаемый .when() – это объект jQuery Promise, охватывающий все исходные запросы ajax. Вы можете позвонить .then() или .fail() чтобы добавить подробные обработчики успеха / отказа.

Если вы хотите дождаться завершения всех запросов ajax в вашем документе, независимо от того, сколько из них существует, просто используйте событие $.ajaxStop таким образом:

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

В этом случае нет необходимости угадывать, сколько запросов может быть в приложении, которое может завершиться в будущем. В некоторых случаях запросы 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 }) 

Интересным моментом здесь является то, что он работает как с Promises и с запросами $.ajax . Вот jsFiddle, демонстрирующий последний.

Я нашел хороший ответ от gnarf my self, который именно то, что я искал 🙂

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

ПРИМЕЧАНИЕ. В приведенных выше ответах используются функциональные возможности, которых не было в момент написания этого ответа. Я рекомендую использовать 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 = $("
"); $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 аякс-запросов, и вы хотите скрыть это сообщение после загрузки.

Из документа jQuery:

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

Обратите внимание, что он будет ждать выполнения всех аякс-запросов на этой странице.

Небольшое обходное решение выглядит примерно так:

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

Надежда может быть полезна …

javascript основан на событиях, поэтому вы никогда не должны ждать , скорее установите привязки / обратные вызовы

Возможно, вы просто используете методы успеха / полного набора 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... } }); 

хотя вы должны опубликовать псевдокод о том, как ваши (а) запросы (-ы) ajax называются точнее …

jQuery позволяет указать, хотите ли вы, чтобы запрос ajax был асинхронным или нет. Вы можете просто сделать запросы ajax синхронными, а остальная часть кода не будет выполняться до тех пор, пока они не вернутся.

Например:

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

На основе ответа @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; }; 

Пример: функция untilAjax использует 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. }); } 

Я настоятельно рекомендую использовать $ .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("
Posts: " + posts.length + "
"); }); // 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("
Posts: " + posts.length + " and Users: " + users.length + "
"); }); // 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("
Delayed Users: " + users.length + "
"); }); }, 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); }); }
  Hi! 

Если вам нужно что-то простое; один раз и сделанный обратный вызов

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

Я встретил эту проблему и создал общий плагин jquery_counter, чтобы решить эту проблему: https://bitbucket.org/stxnext/jquery_counter/

Я нашел простой способ, используя 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 .

Я думаю, что это лучше, чем $., Потому что вы можете объединить все виды асинхронного вызова, который не поддерживает обещания из коробки, такие как таймауты, вызовы SqlLite и т. Д., А не только запросы ajax.

Мое решение таково:

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

Работала очень хорошо. Я пробовал много разных способов сделать это, но я нашел, что это самый простой и многоразовый. Надеюсь, поможет

Посмотрите на мое решение:

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 массив с вашими запросами, вот так:

 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.Создать функцию обратного вызова:

 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 

Решение, данное Алексом, отлично работает. Такая же концепция, но использование ее немного по-другому (когда количество звонков неизвестно заранее)

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

Попробуйте это. создайте цикл внутри 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; } 
  • выбрать событие выбора jquery select
  • Как реализовать иерархический многоуровневый datatable в javaScript?
  • Проблема CORS - заголовок «Access-Control-Allow-Origin» отсутствует на запрошенном ресурсе
  • Событие Click на элементе выбора опции в хроме
  • Преимущества / различия jQuery в .trigger () vs .click ()
  • Слайд справа налево?
  • Добавление / удаление элементов из объекта JavaScript с помощью jQuery
  • MS MVC форма AJAXifying методы
  • Загрузка файлов через AJAX в JQuery
  • Отключение кнопки отправки до тех пор, пока все поля не будут иметь значения
  • Какую версию jQuery следует упомянуть в коде
  • Давайте будем гением компьютера.