为什么即使延迟为 0 毫秒,函数执行后仍会调用 setTimeout 回调?

Why is the `setTimeout` callback called after function execution, even if the delay is 0 ms?

setTimeout(function(){
  console.log("m");
}, 0);
console.log("s");

为什么此代码在 "m" 之前打印 "s",即使 setTimeout 回调应该等待 0 毫秒?

浏览器或node.js总是运行单线程事件循环到运行你的代码。在第一个 运行 上,它总是 运行 您的同步代码,但也可能会查询稍后回调的异步事件。这就是我们在这里调用该函数的原因 callback function 稍后将调用它。

setTimeout 是一个微任务。

这意味着你看到的 function 不是立即执行的,它会首先排队并在下一个事件循环中执行。

还有一个副作用:0 ms 只是意味着它将最少等待 0 ms 不准确 0

当您创建承诺、调用异步函数或将超时设置为 0 毫秒时,该函数会立即排队进入 Javascript event loop。本质上,该函数被添加到要调用的函数队列中,一旦 javascript 解释器无事可做,它就会开始调用这些函数。因此,当您将超时设置为 0 毫秒时,它会将 console.log("m") 排队,然后调用 console.log("s"),然后它无事可做,因此它会完成排队的 console.log("m"),这就是它的原因乱序。

这只是因为 JS 是单线程的,事件循环就是这样工作的。 setTimeout 以一种方式编写,它将向您发送函数或您想要在回调队列中执行的任何操作。 然后前进到下一行,一旦下一行执行它不会运行你的setTimeout部分,或者换句话说,它不会处理setTimeout部分直到堆栈不为空。

所以这是你的代码,它将像这样执行。

 setTimeout(function () {
    console.log("m");
 } , 0)
 console.log('s');
  1. 第一行将执行并将setTimeout的内部发送到回调队列并移动到第二行。
  2. 当第 2 行正在执行 setTimeout 部分时,将等待直到堆栈不为空,一旦第 2 行执行完毕,
  3. setTimeout 部分将执行,

可能说的比较糊涂,我们看实际操作吧。我打赌你找不到比这更好的例子来理解它,它在 the best way by Philip robert.

中有解释

因为JS代码是一条一条的。当您将 setTimeout 指定为 0 时仍在等待,在 C++ lang 中,这将是这样的 0.000000245ms,而 JS 经常在 C++/C 浏览器上运行。

试试这个简单的例子

for (let x = 0; x < 500; x++) {
  setTimeout(() => console.log(x), 0);
}
console.log('hello');