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

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:

let intervalId = setInterval(() => {}, 1000);

Even though the set callback function does nothing useful or interesting, it continues to be called. 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 becomes unnecessary. 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:

let intervalId = setInterval(() => {}, 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(() => {
console.log("now stop");
}, 100);

let intervalId = setInterval(() => {
console.log("running")
}, 1);

intervalId.unref();

You may return a timer to its normal behavior with ref, which will undo an unref method:

let intervalId = setInterval(() => {}, 1000);
intervalId.unref();
intervalId.ref();

The listed process will continue indefinitely, as in our original silly example.

Snap quiz! After running the following code, what is the expected order of logged messages?

const fs = require('fs');
const EventEmitter = require('events').EventEmitter;
let pos = 0;
let messenger = new EventEmitter();

// Listener for EventEmitter
messenger.on("message", (msg) => {
console.log(++pos + " MESSAGE: " + msg);
});

// (A) FIRST
console.log(++pos + " FIRST");

// (B) NEXT
process.nextTick(() => {
console.log(++pos + " NEXT")
})

// (C) QUICK TIMER
setTimeout(() => {
console.log(++pos + " QUICK TIMER")
}, 0)

// (D) LONG TIMER
setTimeout(() => {
console.log(++pos + " LONG TIMER")
}, 10)

// (E) IMMEDIATE
setImmediate(() => {
console.log(++pos + " IMMEDIATE")
})

// (F) MESSAGE HELLO!
messenger.emit("message", "Hello!");

// (G) FIRST STAT
fs.stat(__filename, () => {
console.log(++pos + " FIRST STAT");
});

// (H) LAST STAT
fs.stat(__filename, () => {
console.log(++pos + " LAST STAT");
});

// (I) LAST
console.log(++pos + " LAST");

The output of this program is:

FIRST (A).
MESSAGE: Hello! (F).
LAST (I).
NEXT (B).
QUICK TIMER (C).
FIRST STAT (G).
LAST STAT (H).
IMMEDIATE (E).
LONG TIMER (D).

Let's break the preceding code down:

A, F, and I execute in the main program flow, and as such, they will have the first priority in the main thread. This is obvious; your JavaScript executes its instructions in the order they are written, including the synchronous execution of the emit callback.

With the main call stack exhausted, the event loop is now almost reading to process I/O operations. This is the moment when nextTick requests are honored, slotting in at the head of the event queue. This is when B is displayed.

The rest of the order should be clear. Timers and I/O operations will be processed next, (C, G, H) followed by the results of the setImmediate callback (E), always arriving after any I/O and timer responses are executed.

Finally, the long timeout (D) arrives, being a relatively far-future event.

Note that reordering the expressions in this program will not change the output order outside of possible reordering of the STAT results, which only implies that they have been returned from the thread pool in a different order, remaining as a group in the correct order as related to the event queue.

主站蜘蛛池模板: 濉溪县| 阳山县| 张家界市| 潼南县| 黄浦区| 曲麻莱县| 土默特右旗| 苏尼特左旗| 阳原县| 团风县| 平利县| 乌鲁木齐市| 洪湖市| 墨竹工卡县| 秭归县| 鲁山县| 正安县| 兴业县| 景洪市| 赤水市| 裕民县| 祁东县| 城固县| 仁寿县| 苏尼特左旗| 黔西| 手游| 红原县| 通江县| 江都市| 西乌珠穆沁旗| 虞城县| 呼和浩特市| 广平县| 犍为县| 新津县| 绥阳县| 松江区| 三穗县| 虹口区| 阳春市|