javascript - 意外行为 : Javascript, setTimeout() 和 IIFE

标签 javascript closures settimeout iife

Javascript、事件循环、setTimeout、IIFE、闭包

根据下面的引用资料,我对以下代码的理解是:

setTimeout() 是非阻塞的,由浏览器 Web API 处理,当计时器完成时,它会将回调放入回调队列中。然后事件循环等待调用堆栈空闲以依次运行每个回调。 setTimeout 闭包关闭匿名 IIFE,并为每次迭代提供正确的索引值。

for(var i = 0; i < 3; i++){
    (function(index){
        setTimeout(function(){
            console.log(index);
        }, 5000);
    })(i);
    console.log("loop="+i);
}
/*Output in console is
loop=0
loop=1
loop=2
//after 5 seconds
0
1
2
*/

我正在寻找 Chrome 中以下代码所发生情况的解释。

for (var i = 0; i < 3; i++) {
    setTimeout(
        function(index) { 
            console.log(index);
        }(i), 5000
    );
    console.log("loop="+i);
}
/* Output in console without any delay is:
0
loop=0
1
loop=1
2
loop=2
*/

为什么'console.log(index)'立即执行,没有5秒的延迟?

Web API 如何使用回调作为 IIFE 执行 setTimeout()?

回调队列中是否有回调?

事件循环是否将任何回调移动到调用堆栈?

或者 setTimeout() 被忽略并且它的回调立即在调用堆栈上执行?


我查阅过的引用资料:

Philip Roberts:事件循环到底是什么? | JSConf 欧盟 2014 https://www.youtube.com/watch?v=8aGhZQkoFbQ

Philip Roberts 帮助我陷入事件循环 2016 https://www.youtube.com/watch?v=6MXRNXXgP_0

调用堆栈和事件循环 https://www.youtube.com/watch?v=mk0lu9MKBto

JavaScript closure inside loops – simple practical example

Use IIFE in setTimeout in a loop, but why?

最佳答案

setTimeout(
    function(index) { 
        console.log(index);
    }(i), 5000
);

您正在立即调用传递给setTimeout的第一个参数。当解释器遇到 setTimeout 行时,它首先尝试将其所有参数解析为值。第一个参数是函数调用,因此它调用该函数,期望它将解析为另一个函数 - 就像人们可以做的那样

setTimeout(makeFn('foo'), 5000);

其中 makeFn 返回一个函数。

因此,在您的代码中,

    function(index) { 
        console.log(index);
    }(i)

立即运行,但不返回任何内容 - 解释器将 setTimeout 行解析为

setTimeout(undefined, 5000);

但是 undefined 不是一个函数,因此没有任何异步内容会排队。

这里没有任何 IIFE - 将整个 setTimeout 行放入 IIFE 中:

for (var i = 0; i < 3; i++) {
  ((i) => {
    setTimeout(
      function() {
        console.log(i);
      }, 500
    );
    console.log("loop=" + i);
  })(i);
}

(或者,当然,使用 constlet 而不是 var - 最好避免 var,它的提升和函数范围非常不直观,需要像 for 循环中那样的详细解决方法)

for (let i = 0; i < 3; i++) {
  setTimeout(
    function() {
      console.log(i);
    }, 500
  );
  console.log("loop=" + i);
}

关于javascript - 意外行为 : Javascript, setTimeout() 和 IIFE,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54000574/

相关文章:

javascript - 在我的评分脚本中添加倒计时 (javascript/jquery)

Javascript 闭包 - 无法在 IIFE 函数中保存 "count' 的副本

javascript - 点击计数器(通过闭包)不会增加

javascript - JavaScript 中何时以及如何调用此函数?

javascript - 关于如何重构和改进这个 Javascript 倒计时有什么想法吗? [长代码]

javascript - 转义 JavaScript 事件范围

javascript - 这个javascript模式可以吗?

jquery - jQuery .load() 回调函数中的 CSS 属性

javascript - clearTimeout() 未按预期运行

javascript - notification.confirm 回调不触发 phonegap iOS