2011-05-01 37 views
81

我想,一旦它被执行它在队列中,但在队列中有任何保证它会在X毫秒后精确调用?或者队列中更高的任务会延迟吗?setTimeout如何在Node.JS中工作?

+11

没有非实时操作系统将永远不可能有一个严重的准确性的保证。系统上的各种事情都会(并且会)阻碍定时器机制。 – Pointy 2011-05-01 15:09:29

回答

37

非阻塞的思想是循环迭代很快。所以迭代每个滴答时间应该足够短一段时间,setTimeout将精确到合理的精度(可能是< 100 ms左右)。

虽然理论上你是对的。如果我编写应用程序并阻止勾号,那么setTimeouts将会延迟。所以要回答你的问题,谁可以保证setTimeouts按时执行?通过编写非阻塞代码,您可以控制几乎任何合理程度的准确度。

只要javascript在代码执行(不包括网络工作者等)方面是“单线程”,那将会一直发生。单线程本质在大多数情况下是一种巨大的简化,但要求非阻塞式成语才能成功。

试试这个代码出无论是在浏览器或节点,你会看到,有没有准确的保证,相反,该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 ...

6

确保执行代码的唯一方法是将您的setTimeout逻辑放置在不同的过程中。

使用子进程模块产生一个新的node.js程序,它执行你的逻辑并通过某种流(可能是tcp)将数据传递给该进程。

这种方式即使在你的主进程中运行了一些长的阻塞代码,你的子进程已经自己启动并将一个setTimeout放在一个新进程和一个新线程中,并在你期望的时候运行。

进一步的复杂性是在硬件级别,你有更多的线程运行,然后进程,因此上下文切换将导致(从很小的)延迟,从你的预期时间。这应该是微不足道的,如果重要的话,你需要认真考虑你想要做什么,为什么你需要这样的准确性,以及什么样的实时替代硬件可用来完成这项工作。

一般来说,使用子进程和多个节点应用程序作为独立进程与负载平衡器或共享数据存储(如redis)一起运行对于扩展代码非常重要。

131

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

原因是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. 忙等待5000ms。
  3. 返回到事件循环。检查挂起的定时器并执行。

如果情况并非如此,那么您可能会有一点JavaScript“中断”另一个。我们不得不建立互斥体和semaphors和这样的,以防止这样的代码是非常难推理:

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

节点的JavaScript执行的单threadedness使得它更简单比大多数工作其他风格的并发。当然,这种权衡是因为程序中一个不好表现的部分可能会以无限循环来阻止整个事物。

这是一个更好的恶魔战斗比复杂的抢先?那要看。

+6

你会得到一个非常准确的'console.log'消息的+1。 – 2017-05-01 05:17:26

3

setTimeout是一种线程,它保存给定时间的操作并执行。

setTimeout(function,time_in_mills); 

在这里第一个参数应该是一个函数类型,aexample如果你要打印你的名字在3秒钟后,你的代码应该是下面llike。

setTimeout(function(){console.log('your name')},3000); 

关键poitn要记住的是,你要什么都使用的setTimeout方法去做,做功能里面。如果你想parcing一些参数,你的代码来调用其他方法是类似于下,

setTimeout(function(){yourOtherMethod(parameter);},3000); 

快乐编码的NodeJS :)

3

setTimeout(callback,t)至少使用后运行回调t毫秒。实际延迟取决于许多外部因素,如操作系统计时器粒度和系统负载。

因此,它有可能会在设定的时间后稍微调用,但以前不会调用。

计时器不能超过24.8天。