参考https://stackoverflow.com/a/13951699/929894,我尝试在嵌套的ajax循环中使用延迟对象。但是输出没有按预期返回。我已经用小提琴更新了我的代码以供参考。 - https://jsfiddle.net/fewtalks/nvbp26sx/1/。
CODE:
function main() {
var def = $.Deferred();
var requests = [];
for (var i = 0; i < 2; i++) {
requests.push(test(i));
}
$.when.apply($, requests).then(function() {
def.resolve();
});
return def.promise();
}
function test(x){
var def = $.Deferred();
test1(x).done(function(){
setTimeout(function(){ console.log('processed test item', x); def.resolve();}, 1000);
});
return def.promise();
}
function test1(items){
var _d = $.Deferred();
setTimeout(function(){
console.log('processed test1 item', items);
_d.resolve();
});
return _d.promise();
}
main().done(function(){ console.log('completed')});
代码包含一个执行循环的main函数。在每个循环上,执行子功能(测试)。在子函数(test)内部调用另一个函数(test1)。子函数test和test1都有AJAX调用声明。对于AJAX调用,我使用了setTimeout属性。我期待像
这样的输出processed test1 item0
processed test item0
processed test1 item1
processed test item0
completed
对于每个循环,我希望函数执行为Test1()然后test();但是我得到的结果是
processed test1 item 0
processed test1 item 1
processed test item 0
processed test item 1
completed
执行test1后,执行完全测试功能。为什么函数没有按顺序执行每个循环。
function main(items) {
var items = items;
return items.reduce(function (p, index) {
return p.then(function () {
return test(index);
});
}, $.Deferred().resolve());
}
function test(x) {
var def = $.Deferred();
test1(x).done(function () {
setTimeout(function () {
log('processed test item', x);
def.resolve();
}, 1000);
});
return def.promise();
}
function test1(items) {
var _d = $.Deferred();
setTimeout(function () {
log('processed test1 item', items);
_d.resolve();
});
return _d.promise();
}
var items = [0, 1];
function test2(x) {
var _d = $.Deferred();
setTimeout(function () {
log('processed test2 item',x);
_d.resolve();
});
return _d.promise();
}
main([1,2]).done(function(data){test2(items);}).then(function () {
log('completed')
});
&#13;
<script src="https://dl.dropboxusercontent.com/u/7909102/log.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
&#13;
为什么&#39;已完成&#39;在处理test2函数之前是否已记录?
答案 0 :(得分:2)
您的结果符合预期。
您的for
循环同步运行完成并运行test()
两次。
test()
然后立即调用test1()
,所以你看到的第一件事是test1()
可以运行两次。然后,在每个test1()
完成其承诺后,它会为您的test()
日志消息设置计时器。很自然地,来自test()
的两条日志消息来自test1()
的两条日志消息。
请记住,$.when()
并行运行,因此您传递的所有承诺都会同时进行。
如果您要将您的来电序列化为test(i)
,那么下一个号码要么在第一个号码之后才会发生,那么您需要采取不同的做法。
此外,您在main()
中使用anti-pattern创建了延迟,而不需要创建延迟。您只需返回$.when.apply(...)
即可。你不需要把它换成另一个延期的。
要将您的来电序列化为test(i)
以获取您想要的输出类型,您可以执行以下操作:
function main() {
var items = [0, 1];
return items.reduce(function(p, index) {
return p.then(function() {
return test(index);
});
}, $.Deferred().resolve());
}
生成所需输出的工作演示:https://jsfiddle.net/jfriend00/hfjvjdcL/
此.reduce()
设计模式经常用于串行迭代数组,调用一些异步操作并等待它完成,然后再调用数组中下一项的下一个异步操作。使用.reduce()
是很自然的,因为我们将一个值带到下一次迭代(一个承诺),我们将下一次迭代链接到。它也会返回一个承诺,所以你可以知道整个事情何时完成。