gpt4 book ai didi

javascript - Node.js:setInterval 中的断点

转载 作者:搜寻专家 更新时间:2023-10-31 23:37:35 24 4
gpt4 key购买 nike

我正在使用 setInterval() 调试 node.js( Node 版本 6.2.1)程序在里面。代码非常简单:

const log = console.log;

let cnt = 0;
const inc = () => {
const beforeDebug = Date.now();
log('Before debug time', beforeDebug);

debugger;

const afterDebug = Date.now();
log('After debug time', Date.now());

log('Time spent in debug', afterDebug - beforeDebug);
log(`[${cnt++}]`);
};
setInterval(inc, 1000);

```

我观察到的奇怪行为是 setInterval() 之间的停顿回调执行将取决于我在断点处花费的时间。例如,如果我在“调试器”行停留 10 秒然后恢复,我只会在恢复后 10 秒后看到下一个数字。

我使用命令行 Node 调试器和 Node 检查器检查了此行为。

[更新](为代码添加时间戳)这是在命令行中提取的调试 session 行:

Debugger listening on port 5858
connecting to 127.0.0.1:5858 ... ok

< Before debug time 1467952218915
< After debug time 1467952235018
< Time spent in debug 16103

< Before debug time 1467952252123

基本上,上一节中回调执行的时间差是 17105,几乎正好是 <time-in-debug> + <interval-value>

这个问题没有太大的实际影响,但我很想了解底层的计时器机制。为什么它的行为如此奇怪?

最佳答案

简短的回答是,用于确定何时触发回调的时间是cached。并且可能与回调的实际 insertion time 不同步.

这怎么可能?

要理解为什么会发生这种情况,有助于了解 Node 的计时器是如何实现的(有很好的记录 in the source )。在这里,我们需要记住的是:

  • 回调存储在以超时为键的映射中。例如,当您运行 setTimeout(foo, 10) , 然后 foo将被添加到所有超时回调的列表中 10 .
  • 回调跟踪它们被插入的时间。我们将其称为 insertionTime为简单起见(源代码中实际上是 timer._idleStart)。
  • 当超时开始时, Node 记录当前时间 (now) 并按顺序运行超时的回调,直到没有回调剩余或回调的插入时间为 now - insertionTime < timeout 。 .在最后一种情况下, Node 将 delay the next wakeup of this timeout直到 timeout - (now - insertionTime) .

在您的情况下,会发生以下情况:

  1. t=0 , inc被插入到带有 insertionTime=0 的回调列表中.
  2. t=1000 ,超时唤醒,记录now=1000 ,并运行 inc .
  3. t=3000 (或者不管你调试了多长时间),inc完成并获得 reinserted in the callback list (因为您使用的是 setInterval ),这次是 insertionTime=3000 .
  4. t=3000 , Node 不断遍历回调列表并找到新插入的回调。它计算 now - insertionTime = -2000小于 timeout (因为 now 仍然等于 1000 !)。因此,它安排下一次回调执行 3000 = 1000 - (-2000)几毫秒后。
  5. t=6000 ,超时再次唤醒,记录now=6000 ,并运行 inc .
  6. ...

您可以通过使用 NODE_DEBUG=timer 运行您的程序来了解计时器内部结构。 :

$ NODE_DEBUG=timer node setinterval.js
TIMER 98831: no 1000 list was found in insert, creating a new one
TIMER 98831: timeout callback 1000
TIMER 98831: now: 1067
inc
TIMER 98831: 1000 list wait because diff is -2000
TIMER 98831: timeout callback 1000


TIMER 98831: now: 6072
inc
TIMER 98831: 1000 list wait because diff is -2000
...

据我所知,这看起来像是 Node 中的一个错误。我看不出什么时候负数 diff 才有意义以上。

我们能做些什么?

您似乎是出于好奇才问这个问题,但如果您需要防止这种额外的延迟,您可以通过确保您至少有一个其他回调来应对相同的超时来解决这个问题。这将强制更新到 now .

function f() {
var end = Date.now() + 2000;
while (Date.now() < end); // 2 second busy loop.
console.log('f: ' + Date.now());
}
setInterval(f, 1000);

setTimeout(function () {
setInterval(function () {}, 1000);
}, 10); // Small delay to make sure they don't run in the same wakeup.

如果我们只添加 f ,它最终会每 5 秒运行一次。但是,如果我们还注册了(空的)第二个回调,f将每 3 秒正确运行一次!

关于javascript - Node.js:setInterval 中的断点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38258883/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com