Javascript提升奇怪的行为

时间:2013-02-22 19:17:02

标签: javascript

吊装如何解释这种行为?

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

这是4,4,4,4的输出。

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

3 个答案:

答案 0 :(得分:1)

不是因为它与吊装无关。

即使您将0作为延迟传递,浏览器中的最小延迟也是大约10毫秒。无论你传递什么延迟,该功能都不会立即执行。

来自MDN documentation

  

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

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

相关问题:

答案 1 :(得分: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()调用的结果仍然相同。这是因为无论计划运行的任何异步代码如何,同步流程都会继续。

答案 2 :(得分:0)

在第一个计时器到期之前,四个调用在set循环中激活(并且匿名方法调用将触发)。因此,当它触发时,结果始终为4. setTimeout计时器延迟永远不会得到保证。