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

Why does a setTimeout delay of 0 still run after all other synchronous code in a for loop?

我知道这个问题的版本已经被讨论过,我认为这是独一无二的。为什么延迟为 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 位置:

This is because even though setTimeout was called with a delay of zero, it's placed on a queue and scheduled to run at the next opportunity; not immediately. Currently-executing code must complete before functions on the queue are executed, thus the resulting execution order may not be as expected.

我说的 for 循环是否正确,任何同步代码都放在调用堆栈上 before setTimeout,并且即使您将延迟设置为 0,setTimeout 也会始终运行 仅在 for 循环完成后?否则,为什么延迟为 0,仍然会导致上述行为?

谢谢!

编辑:

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

JavaScript,在浏览器和服务器上,都作为事件循环运行。运行时不断轮询事件。事件包括用户操作(例如 DOM 元素 x 被单击)、I/O(数据从 I/O 或 ajax 调用返回)和计时器事件(在本例中) . setTimeout(fn, 0) 简单地添加一个事件,该事件至少在 0 毫秒过去后由事件循环处理。它总是在处理完当前事件后执行。

Am I correct in saying the for-loop and any synchronous code is placed on the call stack before setTimeout

为了迂腐,setTimeout() 本身被同步调用,并在 console.log(i, 'started'); 之后立即放置在调用堆栈中。它是 settimeout callback(在你的情况下 console.log(i))被排队并被异步调用。