Как дождаться завершения вложенных асинхронных запросов jQuery AJAX?

#javascript #jquery #ajax

#javascript #jquery #ajax

Вопрос:

Я использую jQuery, и у меня есть цикл асинхронных запросов AJAX. Я знаю, что могу дождаться завершения их всех, используя удобный метод ‘$.when.apply(array_of_requests).then()’.

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

Вот упрощенный пример моих запросов:

 var intital_data = [1,2,3,4,5,6,7,8,9,10];
var promises = [];
var promises_inner = [];

$.each(intitial_data, function(i, n) {
    var ajax_call = $.ajax({url:'http://www.domain.com/etc/' n});
    promises.push(ajax_call);

    ajax_call.done(function(data) {
        var ajax_call_inner = $.ajax({url:'http://www.domain.com/etc/' data.result});
        promises_inner.push(ajax_call_inner);

        ajax_call_inner.done(function(data) {
            // Do something with the content of data here.
        });
    });
});
  

Итак, когда каждый из десяти зацикленных AJAX-запросов выполнен, я делаю второй AJAX-запрос на основе результатов первого. Все работает нормально.

Затем у меня есть что-то вроде этого, потому что я хочу дождаться завершения как первых десяти запросов (сохраненных в массиве promises), так и второй партии (сохраненных в promises_inner):

 $.when.apply($, promises).then(
    function() {
        // The ten outer AJAX calls are finished now.

        $.when.apply($, promises_inner).then(
            function() {
                // The inner AJAX calls are finished now.
            }
        );
    }
);
  

В рамках первой функции $.when.apply().then()’s ‘done’ вторая партия запросов еще не завершена или даже не добавлена в массив promises_inner. Но я обнаружил, что добавление вложенного $.when.apply().then(), похоже, работает — в его функции ‘done’ завершены все запросы.

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

Есть ли лучшее, более надежное решение? Спасибо.

Комментарии:

1. Я говорил слишком рано, когда сказал, что это, кажется, работает. Иногда это работает, но в других случаях promises_inner еще не добавил к нему все вложенные AJAX-запросы. Поэтому иногда внутренний $.when происходит до того, как все было возвращено.

Ответ №1:

Взгляните на $.Обратные вызовы в 1.7. Я думаю, вы будете в восторге от гибкости создания собственных «потоков» и возможности их повторного использования, запуска один раз и т.д.

В том, что вы сделали, нет ничего плохого (шаблон apply, возможно, не является первым выбором из большинства, обычно они просто перечисляют их в a $.when(a, b, c ….) — но вам может больше понравиться синтаксис обратных вызовов $.Callbacks.

Комментарии:

1. Спасибо за указатель. Документы $.Callbacks заставляют мой мозг болеть, но я ожидаю, что в конце концов это пройдет! В то же время, считаете ли вы, что мои вложенные $.when … s должны быть надежными?

2. Мы должны делать аналогичные вещи при обработке правил в нашем приложении страхования, потому что задействовано как минимум 10 сервисов. Другая вещь, которую вы можете сделать, которая может быть проще для чтения, — это создать отложенный запрос и разрешить его только после завершения первого запроса when. Используйте это отложенное обещание в качестве . готово для следующего набора обратных вызовов. У Адди Османи есть хорошая статья об обратных вызовах, и, вероятно, скоро появятся новые.

Ответ №2:

Попробуйте это только с одним основным обещанием для полного выполнения (разрешения) за цикл-run (здесь все еще называется inner_promise).

 var initial_data = [1,2,3,4,5,6,7,8,9,10];
var promises_inner = [];

initial_data.forEach(function(n) {
    // Create promise for the inner call here.
    var promise_inner = $.Deferred();
    promises_inner.push(promise_inner);

    $.ajax({url:'http://www.domain.com/etc/' n}).done(function(data) {
        $.ajax({url:'http://www.domain.com/etc/' data.result}).done(function(data) {
            // Do something with the content of data here.
            promise_inner.resolve();
        });
    });
});
console.log("promises_inner contains "   promises_inner.length   " promises") // should contain all the 10 promises

$.when.apply($,promises_inner).done(function() {
    // The inner AJAX calls are finished now
})