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

Javascript how to use setTimeout on an iterative list operation?

本文关键字:setTimeout 操作 列表 迭代 Javascript      更新时间:2023-09-26

我想做这样的事情:

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已经发生了变化。

实现这一点的方法是什么?

模拟JavaScript1.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是非阻塞的。

这就是您可能想要的:

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使每一步都比上一步晚500ms,否则500ms后所有事情都会同时发生。请注意额外的包装函数——它本质上是捕获/保留i的值。

变体之一:

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

只需在超时之前定义函数

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的想法。

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

var _aList = aList;

在循环中,您必须设置Timeout和延迟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);
}