为 setTimeout 和 setImmediate 和 setTimeout 获得不同的结果

Getting different results for setTimeout & setImmediate inside setTimeout

setImmediate(function () {
    console.log('setImmediate')
});

setTimeout(function () {
    console.log('setTimeout')
}, 0);

产出

setTimeout
setImmediate

但是,setTimeout 中的这两个函数输出不同的结果。

setTimeout(function () {
    setImmediate(function () {
        console.log('setImmediate')
    });

    setTimeout(function () {
        console.log('setTimeout')
    }, 0);
}, 0);

输出:

setImmediate
setTimeout

我们知道事件循环看起来像这样-

timers -> IO -> poll -> check ->close -> timers -> ...

计时器:来自 setInterval 或 setTimeout 的回调 IO 回调:来自 I/O 事件的回调 Idle:在 IO 和 Poll 阶段之间由 Node 内部使用 投票:检索新的 I/O 事件 检查:来自 setImmediate 的回调在这里执行 close:像sockets一样处理关闭的连接

在第一个例子中-

我们可以看到 setTimeout 在 setImmediate 之前执行,因为 timer queue 位于 check Queue.

之前

然而在第二种情况下-

当 setTimeout 被执行时,它会触发另一个 setTimeout 和一个 setImmediate,因为 Check queue 被放置在 timer queue 之后,同一循环的检查队列执行 setImmediate,但 嵌套的 setTimeout 被安排在下一个周期

这就是为什么下面的代码也可以用于 运行 定期

let timerId = setTimeout(function tick() {
  alert('tick');
  timerId = setTimeout(tick, 2000); // (*)
}, 2000);

它安排下一次调用,就在第一次调用结束时,这基本上为下一个循环注册了 setTimeout 的调用。