Javascript如何在迭代列表操作中使用setTimeout?

时间:2011-11-12 23:27:05

标签: javascript closures settimeout anonymous-function

我想做这样的事情:

for(var i=0;i<aList.length;i++)
{
    aList[i].doSomething();
    sleep(500);
}

当然,javascript中没有睡眠功能所以我尝试了以下内容:

for(var i=0;i<aList.length;i++)
{
    setTimeout(function(){
        aList[i].doSomething();
    },500);  
}

然而,现在它说没有定义aList [i]。由于匿名函数是一个闭包,它实际上是从外部函数的范围读取aList [i],因此当运行setTimeout中的函数时,i已经改变。

有什么方法可以实现这个目标?

5 个答案:

答案 0 :(得分:6)

模拟JavaScript 1.7 let的快速修复方法是将其包装在函数中:

for(var i=0; i < aList.length; i++) {
    (function(i) {
        setTimeout(function() {
            aList[i].doSomething();
        }, 500 * i); // <-- You need to multiply by i here.
    })(i);
}

我还添加了一个小错误的修复程序,其中脚本将暂停500秒,然后执行所有这些错误。 setTimeout是非阻止的。

答案 1 :(得分:4)

这是你可能想要的:

for(var i=0;i<aList.length;i++)
{
    (function(i){
        // Retain `i` in this scope, for use later (after timeout)
        setTimeout(function(){
           aList[i].doSomething();
        }, 500 * i);
    })(i);
}

你想要500 * i以使每一步比最后一步晚500毫秒,否则一切都会在500毫秒后立即发生。注意额外的包装功能 - 这实际上是陷阱/保留i的值。

答案 2 :(得分:1)

只需在超时前定义功能

for(var i=0; nextFunction = aList[i];i++) {
    var waitAndDoSomething = function(func) {
        return function() { func.doSomething(); }
    };
    setTimeout(waitAndDoSomething(nextFunction),500*i);  
}

另一个可能的答案

在minitect的建议下,我开始考虑其他可能的解决方案。我认为干净的解决方案是使用bind

String.prototype.doSomething = function() { alert(this); } // Just for testing
var aList = ['one', 'two', 'three']; // Just for testing

for(var i=0;obj = aList[i];i++) { 
    setTimeout(obj.doSomething.bind(obj),500*i); 
}

但是,我不确定这在Razor Storm问题的背景下会有多好,因为我不知道aList [i]会代表什么。

这是否回答了问题

我也想知道这是否是预期的行为。它在执行后实际上不会睡觉,而是设定时间。这可能是骗人的,但是如果我们真的想要执行一个函数,然后在下一个函数之前休眠半秒钟,我们的时间就会消失。相反,我会使用递归:

String.prototype.doSomething = function() { alert(this); }
var aList = ['one', 'two', 'three'];

var doNextSomething = function(index) {
    if (!index) { index = 0 }
    if (nextObject = aList[index]) {
        nextObject.doSomething();
        setTimeout(doNextSomething, 500, index + 1);    
    }
};

doNextSomething();

现在,它将在执行函数后等待500毫秒(在长时间运行的任务中很明显)。

我认为所发布的答案更多是Razor Storm所想到的。

答案 3 :(得分:1)

其中一个变种:

var array = [/*elements*/],
    i,
    length = array.length,
    loop = setInterval(function() {
        array[i].doSomething();
        i += 1;
        if (i === length) {
            clearInterval(loop);
        }
    }, 500);

答案 4 :(得分:0)

在for循环之前执行以下操作:

var _aList = aList;

在循环中你需要setTimeout和延迟500 * i。

结果将是:

var _aList = aList;
for(var i=0;i<aList.length;i++)
{
    (function(obj, index) {
        setTimeout(function(){
           obj.doSomething();
        },500 * index); 
    })(aList[i], i);
}