[英]jQuery Deferred/Promises dynamic array not executing callbacks in correct order
感谢任何有关我在这里误解的内容的见解。 我的要求如下:
我有一系列的网址。 我想同时为每个URL发出一个AJAX请求,并在第一个请求完成后立即调用第一个回调。 然后,如果第二个请求完成,请调用该回调,依此类推。
选项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的”。
我显然从根本上误解了承诺的工作方式。 任何帮助感激不尽!
干杯
编辑
好的,现在我更加困惑了。 我使用Alnitak的答案使用一个数组制作了这个JSFiddle ,使用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的承诺,让它在没有它们的情况下工作。 :)
不要忘记您不需要立即注册回调。
我认为这样可行,与你的代码的主要区别在于我使用了.done
而不是.then
并重构了几行。
var promises = myUrlArray.map(function(url) {
return $.ajax({url: url});
});
(function serialize() {
var def = promises.shift();
if (def) {
def.done(function() {
callback.apply(null, arguments);
serialize();
});
}
})();
异步请求不能保证以与发送顺序相同的顺序完成。 有些可能需要更长时间,具体取决于服务器负载和传输的数据量。
唯一的选择是要等到它们全部完成,一次只发送一个,或者只是处理它们可能无序调用。
这是我尝试解决这个问题。 我更新了我的答案,包括失败的.ajax
调用的错误处理。 我还将一些代码移动到.ajax
调用的complete
方法。
var urlArr = ["url1", "url2"];
var responseArr = [];
for(var i = 0; i < length; i++) {
responseArr.push("0");//0 meaning unprocessed to the DOM
}
$.each(urlArr, function(i, url){
$.ajax({
url: url,
success: function(data){
responseArr[i] = data;
},
error: function (xhr, status, error) {
responseArr[i] = "Failed Response";//enter whatever you want to place here to notify the end user
},
complete: function() {
$.each(responseArr, function(i, element){
if (responseArr[i] == "0") {
return;
}
else if (responseArr[i] != "done")
{
//do something with the response
responseArr[i] = "done";
}
});
}
});
})
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.