When I run this code:-
const EventEmitter = require('events')
class Ping extends EventEmitter {
constructor() {
super()
}
}
const myEmitter = new Ping()
myEmitter.on('ping', (arg) => {
console.log("Trigger", arg)
})
I expect the program to hang forever as there is no event emitter, but it stops immediately. As if it 'knows' the event will never be triggered.
And when I run this code:-
const EventEmitter = require('events')
class Ping extends EventEmitter {
constructor() {
super()
}
}
const myEmitter = new Ping()
myEmitter.on('ping', (arg) => {
console.log("Trigger", arg)
})
setTimeout(() => {
myEmitter.emit('ping', "Hello!")
}, 2000)
Program works as expected. Please explain this. Also is there any resource to know how all these methods or node works under the hood?
CodePudding user response:
Nodejs uses a system where in-process asynchronous operations (which include timers) ALL register themselves with with some internals of nodejs. Using this, nodejs knows whether there are any pending or in-process asynchronous operations. A timer that hasn't fired yet, a server that is listening and an open socket are all examples of in-process asynchronous operations.
When there are no pending asynchronous or active operations left, nodejs will automatically exit. As long as there is at least one pending asynchronous operation, nodejs will not exit. The idea is that if there are no pending operations of any kind, then no future events can be created by any means, so nodejs has nothing else to do and will never have anything to do - the app must be finished. No future events in an event-driven system means the app will never do anything in the future - time to exit.
You can actually tell nodejs to ignore a specific asynchronous operation if you want with the .unref()
method. This can be used for lots of things such as timers, sockets, servers, etc... For example, you can see the .unref()
method on a timer here.
In your first code example, you create the emitter, but there are no active asynchronous or live operations so nodejs knows the count of active operations is at zero so it can exit.
In your second code example, you have a timer active which means the count of active operations is non-zero and nodejs does not exit until the timer fires.
You could run a little experiment by doing this:
let timer = setTimeout(() => {
myEmitter.emit('ping', "Hello!")
}, 2000);
// tell nodejs not to wait for this timer
timer.unref();
And, you would find that even your second code block exits immediately because nodejs no longer counts that timer as one of the active operations.