我在节点8.11
上运行此测试脚本:
let end = false;
let i = 0;
setInterval(() => { i++; }).unref();
let k = 0;
async function loop() {
k++
if (end === false)
setImmediate(loop);
}
console.time('test');
loop()
.then(() => {
setTimeout(() => {
end = true;
console.log('interval', i);
console.log('recursion', k);
console.timeEnd('test');
}, 1000);
})
输出为:
interval 997
recursion 824687
test: 1001.831ms
但是,如果我评论这两行:
// if (end === false)
// setImmediate(loop);
结果是:
interval 537
recursion 1
test: 1003.882ms
我对phases of nodejs进行了认真的研究,但是我不明白为什么
setImmediate
应该会影响间隔函数的结果。你有一些解释吗?
谢谢
最佳答案
这是因为在Nodejs上的计时器就不是精确的,因为它们只是事件循环中的事件,所以他们无法确切知道何时触发它们,这就是为什么setTimeout表示它将至少在您提供的时间之后执行。
不能依赖设置的超时间隔来执行
在精确的毫秒数之后。这是因为其他
执行阻止或保留在事件循环中的代码将推动
执行超时返回。唯一的保证就是超时
不会早于声明的超时间隔执行。
设置setInmediate时,您将在事件循环中填充许多中间事件,因此将超时事件推回队列。
请记住,事件循环周期的时间长短不一(确切),因此,即使您认为setInmediate不应影响计时器,您仍将延长事件周期的时间长短。
有趣的文章:
https://nodejs.org/en/docs/guides/timers-in-node/
https://medium.com/the-node-js-collection/what-you-should-know-to-really-understand-the-node-js-event-loop-and-its-metrics-c4907b19da4c
编辑:正如您所指出的,在您的情况下相反,使用setInmediate时会有更多迭代。在那种情况下,这可能与事件循环的速度是动态的有关,取决于程序的负载。