我创建了以下javascript代码:
var index, _i;
var dfd = new $.Deferred();
dfd.resolve();
for (index = _i = 0; _i < 10; index = ++_i) {
$.when($, dfd).done(function() {
console.log('ping');
promise = (function(index) {
setTimeout(function() {
console.log('pong');
dfd.resolve();
}, 3000);
dfd.reject();
})(index);
})
}
在控制台中我看到以下结果
ping
ping
ping
ping
ping
ping
ping
ping
ping
ping
pong
pong
pong
pong
pong
pong
pong
pong
pong
pong
但我想实现
ping
pong
ping
pong
....
我在哪里错了以及如何根据我想要的行为重写代码?
答案 0 :(得分:2)
这是一种方法:
function go(val, t) {
var def = $.Deferred();
setTimeout(function() {
log(val);
def.resolve();
}, t);
return def.promise();
}
function run(numCycles, values, delay) {
function next() {
if (numCycles > 0) {
go(values[0], delay).then(function() {
return go(values[1], delay);
}).then(function() {
--numCycles;
next();
});
}
}
next();
}
run(10, ["ping", "pong"], 500);
工作演示:http://jsfiddle.net/jfriend00/g0Lxm3ws/
从概念上讲,这是如何运作的:
go()
在计时器后输出一条消息。它返回一个在输出消息时解析的promise。run()
接受多个循环和一个由两个值组成的数组,以便在它们之间交替。next()
检查是否还有更多周期要运行,如果是,则将两个go()
个操作链接在一起,当最后一个操作完成时,减少周期数,然后调用再次next()
。您的实施存在各种问题:
$.when()
会收到一份承诺清单,因此$.when($, dfd)
是错误的。$.when()
,因为您可以直接在承诺上使用.then()
。for
循环不会在承诺之间暂停,因此所有"ping"
条消息都会立即显示,然后"pong"
消息会在稍后发布。仅供参考,如果你想循环一个任意数组的值,你可以这样做:
function go(val, t) {
var def = $.Deferred();
setTimeout(function() {
log(val);
def.resolve();
}, t);
return def.promise();
}
function run(numCycles, values, delay) {
function next() {
if (numCycles > 0) {
// create initial resolved promise
// for start of a .reduce() chain
var d = $.Deferred().resolve().promise();
values.reduce(function(p, val){
return p.then(function() {
return go(val, delay);
});
}, d).then(function() {
--numCycles;
next();
});
}
}
next();
}
run(5, ["tic", "tac", "toe"], 500);
答案 1 :(得分:1)
我必须说我不知道你是如何得到这种代码或者你真正想要实现的。但是,至少回答你的第一个问题(出了什么问题?):
一旦延期解决,以后就不会(我相信)被拒绝。它们旨在作为一次性使用对象,如this question中所述。
其次,你在pongs之前得到所有的ping,因为ping的输出机制是同步的(循环)。然而,输出拨弦的机制是异步的 - 超时。因此,在有效的条件下,ping都是在相同的程序实例中输出的,而在3秒之后 - 在输出ping之后很长时间内,它不会启动。