Несколько вызовов ajax ждут последнего для загрузки, затем выполните
У меня есть несколько запросов ajax, запущенных одновременно, и я хочу, чтобы они подождали, пока последний будет возвращен, а затем запустите обработчик успеха во всех вызовах ajax. Для упрощенного примера рассмотрим:
$.ajax({//ajax call 1
url:page1.php,
success: function(data1){
//do something with data1
}
});
....
$.ajax({//ajax call 2
url:page2.php,
success: function(data2){
//do something with data2
}
});
//consider more than just two concurrent requests
Скажем, что все запросы отправляются одновременно. Поскольку они асинхронны, они возвращаются в разное время. Скажем, один запрос принимает 100 мс для возврата, а другой запрос занимает 3000 мс для возврата. Я, очевидно, не знаю, какой из них будет возвращен первым или последним. Все они каким-то образом обновляют DOM, и я хочу, чтобы эти изменения отображались в средстве просмотра одновременно за одно обновление. Как это сделать?
Самое лучшее, о чем я могу думать, - сохранить данные1 и data2 в качестве глобальных переменных. А затем есть переменная счетчика, которая учитывает каждый раз, когда возвращается успех. Затем, на счетчике == TOTAL_NUM_REQUESTS вызывается функция типа updateAll(), затем проходит через все глобальные переменные и помещает их туда, куда им нужно идти. Но это кажется грязным и подверженным ошибкам. Плюс к этому было бы много глобальных переменных.
В идеале я хочу, чтобы обработчики успеха спали по возвращении, а затем при моем состоянии подсчета всех из них, как они были возвращены, отправляйте сообщения о пробуждении всем им, и они могут возобновить выполнение. Это кажется самым чистым, но я не знаю о такой функциональности, как это в javascriptland.
Есть ли у кого-нибудь интересные идеи для этого?
ANSWER UPDATE
Спасибо Ли ниже, я смог получить решение. Мое решение было похоже на его ниже. Я создаю список переменных async
, которые были назначены вызову $.ajax. Изначально обработчик успеха этих вызовов ajax все еще вызывался, поэтому я удалил их и поместил их в другую функцию, которую впоследствии должен был вызвать этот блок when
, который я написал. Я передал results
в функцию, подобную этой:
var results = [];
results.push(async1);
results.push(async2);
... for all the results ...
$.when.apply(this, results).done(function() {
for(var i=0;i<arguments.length;i++){
dataobject=arguments[i][0]
if(dataobject.variousattribute)
mySuccessHandlerFirstGuy(dataobject)
else if(dataobject.anotherattribute)
mySuccessHandlerSecondGuy(dataobject)
//etc ....
}
};
Объект arguments занял немного работы, чтобы выяснить, что это было. Это был массив 2d (список списков). Первый индекс представлял возвращаемый объект, соответствующий заданному запросу ajax. Кажется, что все в порядке, но было бы лучше, если бы ваш сервер вернул то, что вы можете искать, и напишите блок if/else соответственно. Затем в этом элементе в этом списке есть 3 элемента. Первый - это значение, которое было возвращено с сервера, то есть то, что вы хотите. Вторая всегда была строкой success
, которую вы, вероятно, можете использовать, чтобы проверить, работал ли вызов. И третий элемент в этом списке, по-видимому, является первоначальным запросом (хотя я не уверен). Это было бесполезно для меня.
В любом случае, я надеюсь, что это поможет кому-то в будущем. И еще раз спасибо Ли, чтобы указать мне в правильном направлении.
Ответы
Ответ 1
Используйте функцию jQuery $.when(), чтобы запустить что-то, когда закончились все вызовы ajax:
jQuery.when docs
var async1 = $.ajax({//ajax call 1
url:page1.php,
success: function(data1){
//do something with data1
}
});
....
var async2 = $.ajax({//ajax call 2
url:page2.php,
success: function(data2){
//do something with data2
}
});
$.when(async2, async1).done(function(result2, result1) {
... do this when both are successful ...
});
Добавлено в ответ на вопросы:
Если у вас есть куча вызовов ajax, вы можете использовать "apply" следующим образом:
var results = [];
results.push(async1);
results.push(async2);
... for all the results ...
$.when.apply(this, results).done(function() {
... use 'arguments' array to get results ...
});
Ответ 2
Возможно, это будет сделано очень похоже на то, что вы уже предложили.
Сначала создайте глобальные переменные var sleep = true
и var request_count = 0
. Затем запустите таймер, который проверяет request_count
на общее количество запросов каждую секунду или около того. Затем ваши функции успеха могут увеличивать request_counter
, а затем начинать цикл до sleep == false
. Затем, когда функция мониторинга, выполняемая с помощью таймера, обнаруживает request_count == TOTAL_REQUESTS
, она устанавливает sleep = false
, и все ваши функции успеха продолжают об их бизнесе в этой точке.
Ответ 3
Простым решением будет использование модуля PreloaderQ
https://www.npmjs.com/package/preloaderq
Используйте как ниже
var preloader = new PreloaderQ()
preloader.setEmptyCallback(function(){
//all tasks are finished
})
preloader.setFirstTaskCallback(function(){
//started first task
})
preloader.enqueueTask('ajax1')
$.ajax({//ajax call 1
url:page1.php,
success: function(data1){
prealoader.dequeueTask('ajax1')
//do something with data1
}
});
preloader.enqueueTask('ajax2')
$.ajax({//ajax call 1
url:page2.php,
success: function(data2){
prealoader.dequeueTask('ajax2')
//do something with data2
}
});
Вызов emptycallback вызывается после того, как оба завершены