具有动态持续时间的setTimeout函数

时间:2015-06-15 00:57:45

标签: javascript

我有一个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;
&#13;
&#13;

但是,持续时间不是动态的。我也试过parseInt(duration[i]),但这也不起作用。我在这里做错了什么?

-------------澄清-----------------:

据我了解,setTimeout()方法&#34;在指定的毫秒数后调用一个函数或计算表达式&#34; 1。正如上面的抽象代码非常清楚地表明的那样(尽管确定可能需要更多的简短一瞥),对于content数组中的每个项目,都会执行一组操作。每个操作都与一个持续时间(以毫秒为单位)相关联,当前操作应该等到下一个操作开始。

在上面的示例中,在启动函数时,初始等待持续时间10000毫秒(持续时间数组中的第一项)似乎按预期调用。但是,后续操作不会等待持续时间数组中各自值指定的持续时间。

2 个答案:

答案 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]));
}