具有动态持续时间的 setTimeout 函数
setTimeout Function with Dynamic Duration
我有一个迭代值的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])
}
但是,持续时间不是动态的。我也尝试过parseInt(duration[i])
但这也不起作用。我在这里做错了什么?
-------------澄清-----------------:
据我了解,setTimeout() 方法"在指定的毫秒数后调用函数或计算表达式"1。正如上面的抽象代码非常清楚地表明的那样(尽管可能需要不止一眼才能确定),对于content
数组中的每个项目,都有一组要执行的操作。每个操作都与当前操作应等待到下一个操作开始的持续时间(以毫秒为单位)相关联。
在上面的示例中,在启动函数时,初始等待持续时间 10000 毫秒(持续时间数组中的第一项)似乎按预期调用。但是,后续操作不会等待持续时间数组中它们各自值指定的持续时间。
正如另一张海报所提到的,您可能希望每次超时都从最后一个超时的末尾开始。您可以使用建议的"递归"方法,但承诺会产生更具可读性的代码。首先,我们将编写一个wait
例程,该例程返回一个在几毫秒内解析的承诺:
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
使用它们在引擎盖下发挥了它的魔力)。
你可能会说,这似乎需要学习很多东西,只是为了编写一系列连续的超时。但实际上,promise和异步函数最终比编写超时更容易,后者调用函数然后设置其他超时。
递归解决方案
如果您更喜欢递归解决方案,这里有一个稍微简化的版本,它实际上也可以工作(通过最后的()
第一次调用loop
):
function wait_series(duration) {
var i = duration.length;
(function loop() {
if (i--) setTimeout(loop, duration[i]);
})();
^^
}
代码的问题在于 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]));
}
- setTimeout函数能否在其前面的代码执行之前激发
- JS:setTimeout函数的UI计数
- Jasmine:测试setTimeout函数会抛出一个错误
- Javascript/Jquery setTimeout 函数不适用于长 html
- 如何让 setTimeout 函数运行,然后停止使用循环
- 有没有办法覆盖 setTimeout 函数,使其使用微秒而不是毫秒
- setTimeout函数的精确计时
- Javascript-为什么不是't此setTimeout函数正在工作
- 阻止页面重新加载时的setTimeout函数
- 2 setTimeout函数第一个清除第二个javascript
- 如何在 setInterval/setTimeout 函数中按名称调用函数
- Javascript SetTimeOut函数不知怎么不起作用
- Javascript setTimeOut 函数与 .net 中 Windows 应用程序的计时器不匹配
- Javascript setTimeout 函数保持运行
- 当 ajax 返回 1 时如何删除 setTimeout 函数
- setTimeout 函数比它应该的更快
- Javascript:我的setTimeout函数由于第三方而不起作用
- 如何或在哪里将javascript settimeout函数添加到CSS垂直下拉菜单
- 在 javascript 对象中使用方法的值以在 setTimeout 函数中使用
- 如何阻止此 setTimeout 函数运行