官术网_书友最值得收藏!

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.

Tip

At least one thing you may not know about timers...

We are all familiar with the standard arguments to setTimeout: a callback function and timeout interval. Did you know that many additional arguments are passed to the callback function?

setTimeout(callback, time, [passArg1, passArg2…])

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.

主站蜘蛛池模板: 古田县| 丰原市| 楚雄市| 吉隆县| 福清市| 柳江县| 侯马市| 拉萨市| 土默特右旗| 盐边县| 阿克苏市| 龙岩市| 津市市| 德兴市| 昆明市| 瑞金市| 长沙市| 无棣县| 施甸县| 军事| 临朐县| 郯城县| 缙云县| 砀山县| 响水县| 澄江县| 云浮市| 高州市| 磐安县| 伊金霍洛旗| 西青区| 巧家县| 来安县| 酉阳| 永胜县| 盐边县| 汪清县| 富源县| 西平县| 丹寨县| 昔阳县|