【发布时间】:2012-10-29 02:27:14
【问题描述】:
感谢您了解我在这里的误解。我的要求如下:
我有一个 URL 数组。我想同时为每个 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'。
我显然从根本上误解了 Promise 的工作方式。任何帮助都将不胜感激!
干杯
编辑
好吧,现在我更困惑了。我制作了this JSFiddle,其中一个数组使用Alnitak's answer,另一个使用JoeFletch's answer,但它们都没有像我预期的那样工作!谁能看到这里发生了什么?
编辑 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 的承诺,没有它们就可以工作。 :)
【问题讨论】:
-
每个请求的回调是一样的吗?
-
差不多,它只是将返回的 HTML 解析为与请求的 URL 对应的特定元素,并将其插入到 DOM 中。
-
在这种情况下是否可以使用 async:false 选项?
-
@logic8 不幸的是没有,因为请求可能需要相当长的时间才能完成,并且 UI 需要始终保持响应。
标签: javascript jquery asynchronous jquery-deferred promise