Благодарен за любое понимание того, что я здесь неправильно понимаю. Мое требование заключается в следующем:
У меня есть массив URL-адресов. Я хочу запустить запрос AJAX для каждого URL-адреса одновременно, и как только первый запрос завершится, вызовите первый обратный вызов. Затем, если и когда второй запрос завершится, вызовите этот обратный вызов и так далее.
Вариант 1:
for (var i = 0; i < myUrlArray.length; i++) {
$.ajax({
url: myUrlArray[i]
}).done(function(response) {
// Do something with response
});
}
Очевидно, что это не работает, так как нет гарантии, что ответы будут выполнены в правильном порядке.
Вариант 2:
var promises = [];
for (var i = 0; i < myUrlArray.length; i++) {
promises.push($.ajax({
url: myUrlArray[i]
}));
}
$.when.apply($, promises).then(function() {
// Do something with each response
});
Это должно работать, но недостатком является то, что он ожидает завершения всех запросов AJAX, прежде чем запускать любой из обратных вызовов.
В идеале я должен иметь возможность вызвать первый обратный вызов, как только он завершится, затем связать второй обратный вызов для выполнения всякий раз, когда будет получен этот ответ (или немедленно, если он уже разрешен), затем третий и так далее.
Длина массива является полностью переменной и может содержать любое количество запросов в любой момент времени, поэтому просто жестко закодировать цепочку обратного вызова не вариант.
Моя попытка:
var promises = [];
for (var i = 0; i < myUrlArray.length; i++) {
promises.push($.ajax({
url: myUrlArray[i] // Add each AJAX Deferred to the promises array
}));
}
(function handleAJAX() {
var promise;
if (promises.length) {
promise = promises.shift(); // Grab the first one in the stack
promise.then(function(response) { // Set up 'done' callback
// Do something with response
if (promises.length) {
handleAJAX(); // Move onto the next one
}
});
}
}());
Проблема в том, что обратные вызовы выполняются в совершенно случайном порядке! Например, если я добавлю в массив «home.html», «page2.html», «page3.html», порядок ответов не обязательно будет «home.html», «page2.html», «page3». .html».
Я, очевидно, в корне неправильно понимаю что-то о том, как работают обещания. Любая помощь с благодарностью!
Ваше здоровье
ИЗМЕНИТЬ
Ладно, теперь я еще больше запутался. Я сделал это JSFiddle с одним массивом, используя ответ Alnitak и другой, использующий ответ JoeFletch, и ни один из них не работает так, как я бы ожидать! Кто-нибудь может увидеть, что здесь происходит?
ИЗМЕНИТЬ 2
Получил работу! Основываясь на приведенном ниже ответе JoeFletch, я адаптировал решение следующим образом:
var i, responseArr = [];
for (i = 0; i < myUrlArray.length; i++) {
responseArr.push('0'); // <-- Add 'unprocessed' flag for each pending request
(function(ii) {
$.ajax({
url: myUrlArray[ii]
}).done(function(response) {
responseArr[ii] = response; // <-- Store response in array
}).fail(function(xhr, status, error) {
responseArr[ii] = 'ERROR';
}).always(function(response) {
for (var iii = 0; iii < responseArr.length; iii++) { // <-- Loop through entire response array from the beginning
if (responseArr[iii] === '0') {
return; // As soon as we hit an 'unprocessed' request, exit loop
}
else if (responseArr[iii] !== 'done') {
$('#target').append(responseArr[iii]); // <-- Do actual callback DOM append stuff
responseArr[iii] = 'done'; // <-- Set 'complete' flag for this request
}
}
});
}(i)); // <-- pass current value of i into closure to encapsulate
}
TL;DR: я не понимаю промисов jQuery, я заработал без них. :)