为什么setTimeout延迟为0仍然在for循环中的所有其他同步代码之后运行?

时间:2018-03-17 02:31:10

标签: javascript asynchronous closures stack-trace

我已经讨论过这个问题的版本,我认为这是独一无二的。为什么延迟为0仍会导致以下行为。

for(var i = 0; i <3; i ++) {
  console.log(i, 'started');
  setTimeout(()=> {
    console.log(i);
  },0)
  console.log(i, 'done');
}

console.log('loop over');

   // 0 started
   // 0 done
   // 1 started
   // 1 done
   // 2 started
   // 2 done
   // loop over
   // 3 3 3 

到目前为止,我知道认为

引用MDN关于堆栈上的setTimeouts位置:

  

这是因为即使setTimeout被延迟调用了   零,它被放置在队列中并计划在下一个队列中运行   机会;不是马上。当前执行的代码必须完成   在执行队列上的函数之前,由此产生   执行顺序可能不如预期。

我是否正确说for-loop和任何同步代码放在 setTimeout之前的调用堆栈上,即使你将延迟设置为0,setTimeout也总是在for之后运行-loop已经完成了?否则,为什么延迟为0仍会导致上述行为?

谢谢!

编辑:

在开始正确的方向后,我找到了一些视频和一个很好的小工具,向您展示事件循环以及它与此示例代码的关系。这是JS运行时模拟器:loupe

2 个答案:

答案 0 :(得分:2)

JavaScript,无论是在浏览器中还是在服务器上,都作为事件循环运行。运行时不断轮询事件。事件包括用户操作(例如,点击了DOM元素x),I / O(数据从I / O或ajax调用返回)和计时器事件(在这种情况下)。 {0}只需添加一个事件循环处理的事件,至少经过0毫秒。它将始终在处理完当前事件后执行。

答案 1 :(得分:0)

  

我说for-loop和任何同步代码都是正确的   在setTimeout

之前的调用堆栈上

要迂腐,setTimeout()本身会被同步调用,并在console.log(i, 'started');之后立即放在callstack上。它是settimeout 回调(在您的情况下为console.log(i)),它被排队并异步调用。