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

Javascript 为什么在for循环中,setTimeout延迟0仍然在所有其他同步代码之后运行?,javascript,asynchronous,closures,stack-trace,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

我知道已经讨论过这个问题的不同版本,我认为这是独一无二的。为什么延迟为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 
(变量i=0;i)的
{
控制台日志(i);
},0)
console.log(i,“完成”);
}
log('loop-over');
//0开始
//0完成
//1开始
//1完成
//2开始
//2完成
//绕圈子
// 3 3 3 
以下是到目前为止我所知道的:

根据堆栈上的设置超时位置引用MDN:

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

我说的for循环和任何同步代码都是在setTimeout之前放在调用堆栈上的,即使将延迟设置为0,setTimeout也总是在for循环完成后才运行,对吗?否则,为什么延迟0仍然会导致上述行为

谢谢

编辑:


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

JavaScript在浏览器和服务器上都作为事件循环运行。运行时不断轮询事件。事件由用户操作(例如,单击DOM元素x)、I/O(从I/O或ajax调用返回的数据)和计时器事件(在本例中)组成
setTimeout(fn,0)
只需在0毫秒过去时添加事件循环要处理的事件。它将始终在处理当前事件后执行

我说的for循环和任何同步代码被放置是否正确 在setTimeout之前在调用堆栈上


为了学究式,setTimeout()本身被同步调用,并放在
console.log(i,“started”)之后的callstack上。settimeout回调(在您的例子中是
console.log(i)
)排队并异步调用。

Perfect。我发现很多文章都在用这个确切的例子来阐述你所说的。非常感谢你!我发现了一个很好的运行时模拟器,它显示了调用堆栈及其与代码的关系。正如您所说,for循环保持堆栈已满,并且在所有代码完成之前,堆栈不是空的,事件循环无法捕获任何排队的事件。我在上面发布了运行时sim卡。在其他语言中,setTimeOut的作用与这里相同。我们使用此行为来确保所有类的所有其他方法在调用newFunction之前都已调用,并且不需要找到最后一个被调用的方法。