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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5849106/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 19:11:32  来源:igfitidea点击:

How does setTimeout work in Node.JS?

javascriptnode.jsserverside-javascript

提问by MyCodeGone

I guess that once it's executed it's on the queue, but in the queue is there any assurance it will invoke exactly after X milliseconds? Or will other heavy tasks higher on the queue delay it?

我想一旦它被执行,它就在队列中,但在队列中是否有任何保证它会在 X 毫秒后调用?或者队列中的其他繁重任务会延迟它吗?

回答by isaacs

The semantics of setTimeout are roughly the same as in a web browser: the timeout arg is a minimumnumber of ms to wait before executing, not a guarantee. Furthermore, passing 0, a non-number, or a negative number, will cause it to wait a minimum number of ms. In Node, this is 1ms, but in browsers it can be as much as 50ms.

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

The reason for this is that there is no preemption of JavaScript by JavaScript. Consider this example:

这样做的原因是 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')

The flow here is:

这里的流程是:

  1. schedule the timeout for 100ms.
  2. busywait for 5000ms.
  3. return to the event loop. check for pending timers and execute.
  1. 将超时安排为 100 毫秒。
  2. 忙等待 5000 毫秒。
  3. 返回事件循环。检查挂起的计时器并执行。

If this was not the case, then you could have one bit of JavaScript "interrupt" another. We'd have to set up mutexes and semaphors and such, to prevent code like this from being extremely hard to reason about:

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

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

The single-threadedness of Node's JavaScript execution makes it much simpler to work with than most other styles of concurrency. Of course, the trade-off is that it's possible for a badly-behaved part of the program to block the whole thing with an infinite loop.

Node 的 JavaScript 执行的单线程性使其比大多数其他并发风格更易于使用。当然,权衡是程序中行为不良的部分可能会用无限循环阻塞整个过程。

Is this a better demon to battle than the complexity of preemption? That depends.

这是比抢占的复杂性更适合战斗的恶魔吗?那要看。

回答by davin

The idea of non-blocking is that the loop iterations are quick. So to iterate for each tick should take short enough a time that the setTimeout will be accurate to within reasonable precision (off by maybe <100 ms or so).

非阻塞的思想是循环迭代很快。因此,迭代每个滴答应该需要足够短的时间,以便 setTimeout 将准确到合理的精度范围内(可能小于 100 毫秒左右)。

In theory though you're right. If I write an application and block the tick, then setTimeouts will be delayed. So to answer you're question, who can assure setTimeouts execute on time? You, by writing non-blocking code, can control the degree of accuracy up to almost any reasonable degree of accuracy.

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

As long as javascript is "single-threaded" in terms of code execution (excluding web-workers and the like), that will always happen. The single-threaded nature is a huge simplification in most cases, but requires the non-blocking idiom to be successful.

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

Try this code out either in your browser or in node, and you'll see that there is no guarantee of accuracy, on the contrary, the setTimeout will be very late:

在浏览器或节点中尝试此代码,您会发现无法保证准确性,相反,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){}

Unless the interpreter optimises the loop away (which it doesn't on chrome), you'll get something in the thousands. Remove the loop and you'll see it's 500 on the nose...

除非解释器优化循环(它不在 chrome 上),否则你会得到数以千计的东西。取下环,你会看到它在鼻子上是 500...

回答by Raynos

The only way to ensure code is executed is to place your setTimeout logic in a different process.

确保代码得到执行的唯一方法是将您的 setTimeout 逻辑置于不同的进程中。

Use the child process module to spawn a new node.js program that does your logic and pass data to that process through some kind of a stream (maybe tcp).

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

This way even if some long blocking code is running in your main process your child process has already started itself and placed a setTimeout in a new process and a new thread and will thus run when you expect it to.

这样,即使您的主进程中正在运行一些长阻塞代码,您的子进程也已经自行启动并在新进程和新线程中放置了 setTimeout,因此将在您期望的时候运行。

Further complication are at a hardware level where you have more threads running then processes and thus context switching will cause (very minor) delays from your expected timing. This should be neglible and if it matters you need to seriously consider what your trying to do, why you need such accuracy and what kind of real time alternative hardware is available to do the job instead.

更复杂的是在硬件级别,您有更多的线程在运行,然后是进程,因此上下文切换将导致(非常小的)延迟(非常小)。这应该可以忽略不计,如果这很重要,您需要认真考虑您尝试做什么,为什么需要这种准确性以及可以使用什么样的实时替代硬件来完成这项工作。

In general using child processes and running multiple node applications as separate processes together with a load balancer or shared data storage (like redis) is important for scaling your code.

通常,使用子进程并将多个节点应用程序作为单独的进程与负载均衡器或共享数据存储(如 redis)一起运行对于扩展代码很重要。

回答by Ashana.Hymanol

setTimeoutis a kind of Thread, it holds a operation for a given time and execute.

setTimeout是一种Thread,它持有一个给定时间的操作并执行。

setTimeout(function,time_in_mills);

in here the first argument should be a function type; as an example if you want to print your name after 3 seconds, your code should be something like below.

在这里,第一个参数应该是一个函数类型;例如,如果您想在 3 秒后打印您的姓名,您的代码应该如下所示。

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

Key point to remember is, what ever you want to do by using the setTimeoutmethod, do it inside a function. If you want to call some other method by parsing some parameters, your code should look like below:

要记住的关键点是,无论您想使用该setTimeout方法做什么,都可以在函数内部进行。如果你想通过解析一些参数来调用其他方法,你的代码应该如下所示:

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

回答by Siva Prakash

setTimeout(callback,t)is used to run callback after at least t millisecond. The actual delay depends on many external factors like OS timer granularity and system load.

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

So, there is a possibility that it will be called slightly after the set time, but will never be called before.

所以,有可能它会在设定的时间之后被调用,但之前永远不会被调用。

A timer can't span more than 24.8 days.

计时器的跨度不能超过 24.8 天。