Подождите, пока все запросы JQuery Ajax будут выполнены? - PullRequest
623 голосов
/ 14 сентября 2010

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

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

Ответы [ 22 ]

847 голосов
/ 26 марта 2012

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

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

Это означает, что если вы хотите инициировать (например) четыре 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(), чтобы добавить детальные обработчики успеха / неудачи.

277 голосов
/ 26 декабря 2012

Если вы хотите дождаться завершения всех 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 , демонстрирующий последний.

31 голосов
/ 14 сентября 2010

Я нашел хороший ответ от 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);
        }
    });
20 голосов
/ 14 сентября 2010

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

Используйте событие ajaxStop.

Например, предположим, у вас есть сообщение loading ... при получении 100 запросов ajax, и вы хотите скрыть это сообщение после загрузки.

Из jQuery Документ :

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

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

7 голосов
/ 14 сентября 2010

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-запрос (ы) называются, чтобы быть более точными ...

7 голосов
/ 26 октября 2012

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

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

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

4 голосов
/ 15 января 2019

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

$(document).ajaxStop(function() {
     // This function will be triggered every time an ajax is requested and completed
});

Но если вы хотите сделать это для конкретного запроса ajax(), лучшее, что вы можете сделать, этоиспользуйте метод complete() внутри определенного запроса ajax:

$.ajax({
    type: "POST",
    url: "someUrl",
    success: function(data) {
        // This function will be triggered when ajax returns a 200 status code (success)
    },
    complete: function() {
        // This function will be triggered always, when ajax request is completed, even it fails/returns other status code
    },
    error: function() {
        // This will be triggered when ajax request fail.
    }
});
2 голосов
/ 14 сентября 2010

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

Например:

jQuery.ajax({ 
    async: false,
    //code
});
1 голос
/ 05 ноября 2018

Я использую проверку размера после завершения загрузки ajax

function get_ajax(link, data, callback) {
    $.ajax({
        url: link,
        type: "GET",
        data: data,
        dataType: "json",
        success: function (data, status, jqXHR) {
            callback(jqXHR.status, data)
        },
        error: function (jqXHR, status, err) {
            callback(jqXHR.status, jqXHR);
        },
        complete: function (jqXHR, status) {
        }
    })
}

function run_list_ajax(callback){
    var size=0;
    var max= 10;
    for (let index = 0; index < max; index++) {
        var link = 'http://api.jquery.com/ajaxStop/';
        var data={i:index}
        get_ajax(link,data,function(status, data){
            console.log(index)
            if(size>max-2){
                callback('done')
            }
            size++
            
        })
    }
}

run_list_ajax(function(info){
    console.log(info)
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...