- Mastering Node.js
- Sandro Pasquali
- 960字
- 2021-07-21 18:17:13
Timers
Timers are used to schedule events in the future. They are used when one seeks to delay the execution of some block of code until a specified number of milliseconds have passed, to schedule periodic execution of a particular function, or to slot some functionality immediately to the following.
JavaScript provides two asynchronous timers: setInterval()
and setTimeout()
.
It is assumed that the reader is fully aware of how to set (and cancel) these timers, so very little time will be spent discussing the syntax. We'll instead focus more on "gotchas" and "less well-known" details about timeouts and intervals.
The key takeaway will be this: when using timers one should make no assumptions about the amount of actual time that will expire before the callback registered for this timer fires, or about the ordering of callbacks. Node timers are not interrupts. Timers simply promise to execute as close as possible to the specified time (though never before), beholden, as with every other event source, to event loop scheduling.
setTimeout
Timeouts are used to defer the execution of a function until some number of milliseconds into the future:
Consider the following code:
setTimeout(a, 1000); setTimeout(b, 1001);
One would expect that function b
would execute after function a
. However, this cannot be guaranteed—a
may follow b
, or the other way around.
Now, consider the subtle difference present in the following code snippet:
setTimeout(a, 1000); setTimeout(b, 1000);
The execution order of a
and b
are predictable in this case. Node essentially maintains an object map grouping callbacks with identical timeout lengths. Isaac Schlueter, the current leader of the Node project, puts it this way:
[N]ode uses a single low level timer object for each timeout value. If you attach multiple callbacks for a single timeout value, they'll occur in order, because they're sitting in a queue. However, if they're on different timeout values, then they'll be using timers in different threads, and are thus subject to the vagaries of the [CPU] scheduler. |
||
--https://groups.google.com/forum/#!msg/nodejs-dev/kiowz4iht4Q/T0RuSwAeJV0J |
The ordering of timer callbacks registered within an identical execution scope does not predictably determine the eventual execution order in all cases.
Additionally, there exists a minimum wait time of one millisecond for a timeout. Passing a value of zero, -1, or a non-number will be translated into thisminimum value.
setInterval
One can think of many cases where being able to periodically execute a function would be useful. Polling a data source every few seconds and pushing updates is a common pattern. Running the next step in an animation every few milliseconds is another use case, as is collecting garbage. For these cases setInterval
is a good tool:
var intervalId = setInterval(function() { ... }, 100);
Every 100 milliseconds the sent callback function will execute, a process that can be cancelled with clearInterval(intervalId)
.
Unfortunately, as with setTimeout
, this behavior is not always reliable. Importantly, if a system delay (such as some badly written blocking while
loop) occupies the event loop for some period of time, intervals set prior and completing within that interim will have their results queued on the stack. When the event loop becomes unblocked and unwinds, all the interval callbacks will be fired in sequence, essentially immediately, losing any sort of timing delays they intended.
Luckily, unlike browser-based JavaScript, intervals are rather more reliable in Node, generally able to maintain expected periodicity in normal use scenarios.
unref and ref
A Node program does not stay alive without a reason to do so. A process will keep running for as long as there are callbacks still waiting to be processed. Once those are cleared, the Node process has nothing left to do, and it will exit.
For example, the following silly code fragment will keep a Node process running forever:
Var intervalId = setInterval(function() {}, 1000);
Even though the set callback function does nothing useful or interesting, it continues to be called—and this is the correct behavior, as an interval should keep running until clearInterval
is used to stop it.
There are cases of using a timer to do something interesting with external I/O, or some data structure, or a network interface where once those external event sources stop occurring or disappear, the timer itself stops being necessary. Normally one would trap that irrelevant state of a timer somewhere else in the program and cancel the timer from there. This can become difficult or even clumsy, as an unnecessary tangling of concerns is now necessary, an added level of complexity.
The unref
method allows the developer to assert the following instructions: when this timer is the only event source remaining for the event loop to process, go ahead and terminate the process.
Let's test this functionality to our previous silly example, which will result in the process terminating rather than running forever:
var intervalId = setInterval(function() {}, 1000); intervalId.unref();
Note that unref
is a method of the opaque value returned when starting a timer (which is an object).
Now let's add an external event source, a timer. Once that external source gets cleaned up (in about 100 milliseconds), the process will terminate. We send information to the console to log what is happening:
setTimeout(function() { console.log("now stop"); }, 100); var intervalId = setInterval(function() { console.log("running") }, 1); intervalId.unref();
You may return a timer to its normal behavior with ref
, which will undo an unref
method:
var intervalId = setInterval(function() {}, 1000); intervalId.unref(); intervalId.ref();
The listed process will continue indefinitely, as in our original silly example.
- 數據科學實戰手冊(R+Python)
- 精通Nginx(第2版)
- JavaScript 從入門到項目實踐(超值版)
- Python自然語言處理實戰:核心技術與算法
- Java Web程序設計
- PHP 編程從入門到實踐
- Backbone.js Blueprints
- Learning Vaadin 7(Second Edition)
- 從零開始學C#
- Learning PHP 7
- UI設計全書(全彩)
- R數據科學實戰:工具詳解與案例分析
- 一步一步學Spring Boot:微服務項目實戰(第2版)
- ASP.NET Core 2 High Performance(Second Edition)
- Practical Time Series Analysis