我想一旦它被执行,它就在队列中,但在队列中是否有任何保证它会在 X 毫秒后调用?或者队列中的其他繁重任务会延迟它吗?
setTimeout 在 Node.JS 中是如何工作的?
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')
这里的流程是:
- 将超时安排为 100 毫秒。
- 忙等待 5000 毫秒。
- 返回事件循环。检查挂起的计时器并执行。
如果不是这种情况,那么您可以让 JavaScript 的一个位“中断”另一个。我们必须设置互斥体和信号量等,以防止像这样的代码非常难以推理:
var a = 100;
setTimeout(function () {
a = 0;
}, 0);
var b = a; // 100 or 0?
Node 的 JavaScript 执行的单线程性使其比大多数其他并发风格更易于使用。当然,权衡是程序中行为不良的部分可能会用无限循环阻塞整个程序。
这是比抢占的复杂性更适合战斗的恶魔吗?那要看。
非阻塞的想法是循环迭代很快。因此,迭代每个刻度应该花费足够短的时间,以便 setTimeout 将准确到合理的精度范围内(可能小于 100 毫秒左右)。
虽然理论上你是对的。如果我编写一个应用程序并阻止滴答声,那么 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...
setTimeout
是一种Thread,它持有一个给定时间的操作并执行。
setTimeout(function,time_in_mills);
在这里,第一个参数应该是函数类型;例如,如果您想在 3 秒后打印您的姓名,您的代码应该如下所示。
setTimeout(function(){console.log('your name')},3000);
要记住的关键点是,无论您想使用该setTimeout
方法做什么,都可以在函数内部进行。如果你想通过解析一些参数来调用其他方法,你的代码应该如下所示:
setTimeout(function(){yourOtherMethod(parameter);},3000);
确保代码得到执行的唯一方法是将 setTimeout 逻辑放在不同的进程中。
使用子进程module生成一个新的 node.js 程序,该程序执行您的逻辑并将数据通过某种流(可能是 tcp)传递给该进程。
这样,即使您的主进程中正在运行一些长阻塞代码,您的子进程也已经自行启动并在新进程和新线程中放置了 setTimeout,因此将在您期望的时候运行。
更复杂的是在硬件级别,您有更多的线程在运行,然后是进程,因此上下文切换将导致(非常小的)延迟(非常小)。这应该可以忽略不计,如果这很重要,您需要认真考虑您尝试做什么,为什么需要如此精确以及可以使用什么样的实时替代硬件来完成这项工作。
通常,使用子进程并将多个节点应用程序作为单独的进程与负载均衡器或共享数据存储(如 redis)一起运行对于扩展代码很重要。
setTimeout(callback,t)
用于在至少 t 毫秒后运行回调。实际延迟取决于许多外部因素,如操作系统计时器粒度和系统负载。
所以,有可能它会在设定的时间之后被调用,但之前永远不会被调用。
计时器的跨度不能超过 24.8 天。