【问题标题】:setTimeout() triggers a little bit earlier than expectedsetTimeout() 比预期早一点触发
【发布时间】:2018-04-17 13:01:36
【问题描述】:

UPD:问题What is the reason JavaScript setTimeout is so inaccurate? 询问为什么JavaScript 中的计时器通常不准确,并且所有提到的不准确都是关于在指定延迟之后稍稍的调用。在这里,我问为什么 NodeJS 甚至在延迟之前也容忍调用?定时器的设计不是容易出错吗?

刚刚发现 NodeJS setTimeout() 的意外行为(仅对我而言?)。有时它会比指定的延迟更早触发。

function main() {
  let count = 100;
  while (count--) {
    const start = process.hrtime();
    const delay = Math.floor(Math.random() * 1000);

    setTimeout(() => {
      const end = process.hrtime(start);
      const elapsed = (end[0] * 1000 + end[1]/1e6);
      const dt = elapsed - delay;
      if (dt < 0) {
        console.log('triggered before delay', delay, dt);
      }
    }, delay);
  }
}

main();

在我的笔记本电脑上的输出是:

$ node --version
$ v8.7.0

$ node test.js
triggered before delay 73 -0.156439000000006
triggered before delay 364 -0.028260999999986325
triggered before delay 408 -0.1185689999999795
triggered before delay 598 -0.19596799999999348
triggered before delay 750 -0.351709000000028

它是事件循环的“特性”吗?我一直认为至少要在delayms之后触发。

【问题讨论】:

  • 我已经复制了这个问题。我试图将setTimeout(...) 放在IIFE 中,就像(function(start, delay) { ... })(start, delay); 一样,它似乎减少了在预期之前触发的事件数量。但我仍然没有解释。
  • 延迟时间只有几分之一毫秒。我认为这与您将获得的一样好。
  • 为什么会被否决?这个问题是完全有效的。我刚刚遇到了一个损坏的测试用例,因为它预计超时为至少指定的毫秒数。一开始我并没有意识到这个错误。

标签: javascript node.js settimeout event-loop


【解决方案1】:

来自NodeJS docs

回调可能不会在精确的延迟毫秒内被调用。 Node.js 不保证回调何时触发的确切时间,也不保证它们的顺序。回调将在尽可能接近指定时间时被调用。

随着间隔数的增加(您有 100 个),准确度会降低,例如,1000 个间隔的准确度会更差。有十个就好多了。由于 NodeJS 必须跟踪更多的间隔,它的准确性会降低。

我们可以假设该算法有一个“合理的增量”来确定最终的准确性,并且它不包括检查以确保它在指定的时间间隔之后。也就是说,通过挖掘源代码很容易找到。

另请参阅How is setTimeout implemented in node.js,其中包含更多详细信息,初步来源调查似乎证实了这一点和上述。

【讨论】:

  • 我不希望它恰好在delay ms 之后被调用。我只是希望它在 delay 之后被调用。但在我的示例中,它之前被调用过。
  • 表达式“尽可能接近指定时间”并不意味着在指定时间之后。可能是以前。 question linked in the comments 提供更多信息。
  • @IvanVelichko “尽可能接近”对之前/之后没有任何影响。在这样的环境中,IMO 的不准确是可以预料的。还要考虑您正在加载间隔数;间隔数越少,不准确性就越小,间隔越多,情况就越糟。由于它必须检查更多的间隔,它的准确性会降低,并且它使用任何算法来查看间隔是否“足够接近”将决定最终的准确性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-03
  • 2014-08-28
  • 1970-01-01
相关资源
最近更新 更多