0

提升如何解释这种行为?

for(var i = 0; i < 4; i++) {
    setTimeout(function() {
        alert("i is: " + i);
    }, i * 200);
}

其输出为 4、4、4、4。

这在文献中经常被用作一个危险的起重例子。后面的输出可能是 4 是有道理的,因为 i 变量绑定到函数范围,因此在所有调用之间共享,并且在它们执行时 i 将是 4 完成 for 循环。但是,初始调用指定了 0 * 200 或 0 的超时,因此我觉得这应该在 i 仍然小于 4 时立即执行。是什么导致该函数的所有输出都是 4?

4

3 回答 3

1

这不是因为它与吊装无关。

即使你0作为延迟传递,浏览器中的最小延迟也是 10 毫秒左右。无论您通过什么延迟,该函数都不会立即执行。

MDN 文档

setTimeout()请务必注意,如果在调用的线程终止之前无法执行函数或代码片段。

因此,在调用任何回调之前,for循环已经终止。

相关问题:

于 2013-02-22T19:22:06.547 回答
1

“但是,初始调用指定了 0 * 200 或 0 的超时,因此我觉得这应该立即执行......”

这可能发生在可以利用多线程的环境中,但在单线程环境中,当前的同步执行流程将继续不受限制,直到完成。

这意味着循环在第一次setTimeout回调发生之前继续并完成。

即使您的循环需要10,000 毫秒才能完成,在第一个回调触发之前,循环也将被允许继续。


试试这个演示:

var start = Date.now();

for(var i = 0; i < 4; i++) {

     // set up the first timeout
    setTimeout(function() {
        alert("i is: " + i);
    }, i * 200);

    while (Date.now() - start < 1000) ; // block for 1000 ms
}

第一个setTimeout设置完成后,我们阻塞 1000 毫秒。调用的结果alert()还是一样的。这是因为无论计划运行的任何异步代码如何,同步流程都会继续进行。

于 2013-02-22T19:22:14.573 回答
0

在第一个计时器到期之前,对 setTimeout的四次调用在循环内触发(并且匿名方法调用触发)。结果,当它触发时,结果始终为 4。 setTimeout 计时器延迟永远无法保证。

于 2013-02-22T19:25:35.497 回答