Jquery 在每个循环中延迟 ajax 回调
Jquery Deferred in each loop with ajax callback
参考, I tried using deferred object in nested ajax loop. However the output is not returning as expected. I have updated my code in fiddle for reference. - https://jsfiddle.net/fewtalks/nvbp26sx/1/。
代码:
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')});
代码包含一个执行循环的主函数。在每个循环中,执行一个子函数(测试)。在子函数(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')
});
<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>
为什么在处理 test2 函数之前记录 'completed'?
你的结果符合预期。
您的 for
循环 运行s 同步完成并 运行s test()
两次。
test()
然后立即调用 test1()
所以你首先看到的是 test1()
两次到达 运行。然后,在每个 test1()
完成其承诺后,它会为您的 test()
日志消息设置计时器。很自然地,来自 test()
的两条日志消息出现在来自 test1()
.
的两条日志消息之后
记住 $.when()
运行 事情是并行的,所以你传递给它的所有承诺都是同时进行的。
如果您想序列化对 test(i)
的调用,以便下一个调用不会在第一个调用之后发生,那么您需要采取不同的方式。
此外,您在 main()
中使用了 anti-pattern,方法是在不需要创建延迟的地方创建延迟。你可以 return $.when.apply(...)
。你不需要将它包装在另一个 deferred 中。
要序列化对 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()
是很自然的,因为我们将一个值传递给我们将下一次迭代链接到的下一次迭代(承诺)。它还 return 也是一个承诺,因此您可以知道整个事情何时完成。
参考, I tried using deferred object in nested ajax loop. However the output is not returning as expected. I have updated my code in fiddle for reference. - https://jsfiddle.net/fewtalks/nvbp26sx/1/。
代码:
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')});
代码包含一个执行循环的主函数。在每个循环中,执行一个子函数(测试)。在子函数(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')
});
<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>
为什么在处理 test2 函数之前记录 'completed'?
你的结果符合预期。
您的 for
循环 运行s 同步完成并 运行s test()
两次。
test()
然后立即调用 test1()
所以你首先看到的是 test1()
两次到达 运行。然后,在每个 test1()
完成其承诺后,它会为您的 test()
日志消息设置计时器。很自然地,来自 test()
的两条日志消息出现在来自 test1()
.
记住 $.when()
运行 事情是并行的,所以你传递给它的所有承诺都是同时进行的。
如果您想序列化对 test(i)
的调用,以便下一个调用不会在第一个调用之后发生,那么您需要采取不同的方式。
此外,您在 main()
中使用了 anti-pattern,方法是在不需要创建延迟的地方创建延迟。你可以 return $.when.apply(...)
。你不需要将它包装在另一个 deferred 中。
要序列化对 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()
是很自然的,因为我们将一个值传递给我们将下一次迭代链接到的下一次迭代(承诺)。它还 return 也是一个承诺,因此您可以知道整个事情何时完成。