setTimeout 在 Node.JS 中是如何工作的?

我猜一旦它被执行,它就在队列中,但是在队列中,有什么保证它会在X毫秒后调用吗?还是队列上更高的其他繁重任务会延迟它?


答案 1

setTimeout 的语义与 Web 浏览器中的语义大致相同:超时参数是执行前要等待的最小毫秒数,而不是保证。此外,传递 0、非数字或负数将导致它等待最小毫秒数。在 Node 中,这是 1 毫秒,但在浏览器中,它可以高达 50 毫秒。

这样做的原因是 JavaScript 没有抢占 JavaScript。请考虑以下示例:

setTimeout(function () {
  console.log('boo')
}, 100)
var end = Date.now() + 5000
while (Date.now() < end) ;
console.log('imma let you finish but blocking the event loop is the best bug of all TIME')

这里的流程是:

  1. 将超时安排为 100 毫秒。
  2. 忙等待 5000 毫秒。
  3. 返回到事件循环。检查挂起的计时器并执行。

如果不是这样,那么你可以让一个JavaScript“中断”另一个。我们必须设置互斥体和信号量等,以防止像这样的代码非常难以推理:

var a = 100;
setTimeout(function () {
  a = 0;
}, 0);
var b = a; // 100 or 0?

Node的JavaScript执行的单线程性使其比大多数其他并发样式更易于使用。当然,权衡是程序中行为不端的部分可能会用无限循环来阻止整个事情。

这是比抢占的复杂性更好的恶魔吗?这要视情况而定。


答案 2

非阻塞的想法是循环迭代很快。因此,要迭代每个价格变动,应该需要足够短的时间,以便 setTimeout 精确到合理的精度范围内(偏差可能为 <100 毫秒左右)。

从理论上讲,你是对的。如果我写了一个应用程序并阻止了勾选,那么setTimeouts将被延迟。因此,要回答您的问题,谁可以确保setTimeouts按时执行?通过编写非阻塞代码,您可以控制精确度,几乎达到任何合理的准确度。

只要javascript在代码执行方面是“单线程”的(不包括Web工作者等),这种情况就会永远发生。在大多数情况下,单线程性质是一个巨大的简化,但需要非阻塞习语才能成功。

在浏览器或节点中尝试此代码,您会发现无法保证准确性,相反,setTimeout 将非常晚:

var start = Date.now();

// expecting something close to 500
setTimeout(function(){ console.log(Date.now() - start); }, 500);

// fiddle with the number of iterations depending on how quick your machine is
for(var i=0; i<5000000; ++i){}

除非解释器优化循环(它在chrome上没有),否则你会得到成千上万的东西。去掉环,你会看到它在鼻子上是500...