3

我有一个 for 循环,我需要在其中延迟每次重复以用于动画目的。如果我删除 setTimeOut 函数,则以下代码会正确循环,并且变量会通过循环正确递增,然后执行底线。但是使用 setTimeoout 函数,底线先执行,然后 for 循环执行 7 次(应该是 6 次),每次都告诉我 x = 6。显然我做错了什么。有任何想法吗?

for ( x = 0; x <= 5; x++) {
    setTimeout(function() {
        alert("For loop iteration #" + x);
    }, 500 * x);
}
alert("Code to be executed after completed for loop");
4

3 回答 3

5

您需要一个闭包来x在闭包上下文中保存当前值。

 for (var x = 0; x <= 5; x++) {
    (function(x) {
        setTimeout(function(){
            alert("For loop iteration #" + x);
            if (x == 5) {
                setTimeout(function(){
                    alert("Code to be executed after completed for loop");
                });
            }
        }, 5 * x);

    })(x);
}
于 2013-03-10T21:21:01.587 回答
3

这是一个常见的概念错误。

  1. Javascript 是非阻塞的
  2. 传递了对变量的引用,而不是实际值

您必须记住,变量x是动态的。引用x传递给alert("For loop iteration #" + x);非值。因此,当alertfinally 被执行x时将具有它在执行点而不是在setTimeout启动点的值!

本质上它是这样的:
处理你的循环,创建 6 个超时,然后立即显示你的alert("Code to be executed after completed for loop");. 然后在一段时间后,您的超时将被执行,然后在循环完成后将所有显示变量 x 的状态 - 6

您需要一个闭包,以便将值x传递给警报,而不是对变量x本身的引用。

for (var x = 0; x <= 5; x++) {
    (function(z) {
        setTimeout(function() {
            alert("For loop iteration #" + z);
        }, 5 * z);
    })(x);
}

编辑:

要解决第二个问题,您需要使用回调函数。CB 函数是您的代码的逻辑延续,但不应立即执行,而是需要暂停到某个点(您的最后一个警报已发生)。你会像这样实现它:

for (var x = 0; x <= 5; x++) {
    (function(z) {
        setTimeout(function() {
            alert("For loop iteration #" + z);
            if (z===5){ continue_code() }
        }, 5 * z);
    })(x);
}

function continue_code(){
    alert("Code to be executed after completed for loop");
    // Here comes all your code
    // which has to wait for the timeouts from your for loop
}

在最后一个 setTimeout 中,您调用继续执行代码的函数。

于 2013-03-10T21:21:27.640 回答
1

x 是一个全局变量。在第一个警报发生时,您已将其增加到 6。如果您不希望这种情况发生,请改用类似的方法,它在每 500 毫秒调用一次的函数内部递增:

var x = 0;
var interval = setInterval(function() {
    alert("Loop iteration #" + x++);
    if(x==5) {
        clearInterval(interval);
        alert("Code to be executed after completing loop");
    }
}, 500);
于 2013-03-10T21:19:00.150 回答