我在节点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时会有更多迭代。在那种情况下,这可能与事件循环的速度是动态的有关,取决于程序的负载。

09-29 23:12