我有一个setTimeout函数,它迭代值:
var content = ['one', 'two', 'three', 'four', 'five']
var duration = ['10000', '10000', '20000', '10000', '30000']
for (i = 0; i < content.length; i++) {
setTimeout(function () {
alert("hi")
}, duration[i])
}
&#13;
但是,持续时间不是动态的。我也试过parseInt(duration[i])
,但这也不起作用。我在这里做错了什么?
-------------澄清-----------------:
据我了解,setTimeout()方法&#34;在指定的毫秒数后调用一个函数或计算表达式&#34; 1。正如上面的抽象代码非常清楚地表明的那样(尽管确定可能需要更多的简短一瞥),对于content
数组中的每个项目,都会执行一组操作。每个操作都与一个持续时间(以毫秒为单位)相关联,当前操作应该等到下一个操作开始。
在上面的示例中,在启动函数时,初始等待持续时间10000毫秒(持续时间数组中的第一项)似乎按预期调用。但是,后续操作不会等待持续时间数组中各自值指定的持续时间。
答案 0 :(得分:2)
正如另一张海报所提到的,你可能希望每个超时都从最后一个超时开始。您可以使用建议的“递归”方法,但 promises 会产生更易读的代码。首先,我们将编写一个wait
例程,该例程返回一个在几毫秒内解析的promise:
function wait(n) {
return new Promise(function(resolve) { setTimeout( resolve, n); });
}
现在我们可以按如下方式重写你的循环:
var promise = Promise.resolve();
for (i = 0; i < content.length; i++) {
promise = promise . then(function() { return wait(duration[i]; });
}
我们需要Promise.resolve()
来解决已经解决的承诺。顺便说一句,作为奖励,在这个循环结束时,你有一个完成的整个超时链的承诺,你可以用来做下一步。
事实证明这与
完全相同duration.reduce(
function(promise, ms) {
return promise . then(function() { return wait(ms); });
}, Promise.resolve()
);
如果您不知道reduce
,那么值得学习。
但是想象一下,跳过这一切是多么好,只是有一些东西而不是设置超时,等待就在那里。事实证明,您可以使用async
函数执行此操作:
async function wait_series(duration) {
^^^^^
for (i = 0; i < content.length; i++) {
await wait(duration[i]);
^^^^^
}
}
异步函数将需要使用适当的标记符(例如babel)使用适当的标记符。
如果您没有或想要使用Babel,但可以访问生成器,则可以使用co
之类的库来转换生成器(function*
)进入异步函数,yield
在哪里等待:
function wait_series(duration) {
co(function *() {
^^
for (i = 0; i < content.length; i++) {
yield wait(duration[i]);
^^^^^
}
});
}
使用异步函数或基于co
的等价函数的优点是,您可以像往常一样回到编写常规的旧for
循环。它们本质上允许您使用同步思维模式编写异步代码。你不再需要考虑承诺(虽然co
使用它们可以发挥它的神奇作用。)
你可能会说,这似乎只是为了编写一系列连续的超时而学习的东西。但实际上,承诺和异步函数最终更容易,而不是编写调用函数然后设置其他超时的超时。
如果您更喜欢递归解决方案,这里有一个稍微简化的版本,它实际上也有效(通过最后通过loop
调用()
):
function wait_series(duration) {
var i = duration.length;
(function loop() {
if (i--) setTimeout(loop, duration[i]);
})();
^^
}
答案 1 :(得分:0)
代码的问题在于for循环迭代而不等待setTimeout完成 我建议像这样使用一些递归
var content = ['one','two','three','four','five'];
var duration = ['10000','10000','20000','10000','30000'];
var i = 0;
var loop = function(){
setTimeout(function(){
if(++i < content.length);
loop();
},parseInt(duration[i]));
}