In the following code, I assign a listener to the data
event of process.stdin
with the once
method.
console.log('Press Enter to allow process to terminate')
process.stdin.once('data', callback)
function callback (data) {
console.log('Process can terminate now')
}
In theory, when the callback has fired, the event listener should be automatically removed (because I attached it with once
), allowing the process to terminate. Surprisingly, in this case, the process never terminates (The code you see is the whole thing, try it!). I also tried manually removing the listener, but that changes nothing.
Is there something else going on here that I don't realise perhaps?
Method 1: Using ctrl+C key: When running a program of NodeJS in the console, you can close it with ctrl+C directly from the console with changing the code shown below: Method 2: Using process. exit() Function: This function tells Node. js to end the process which is running at the same time with an exit code.
close() prevents new connections and waits until all the clients are closed. To forcibly kill a node server you need to call server. close() and then close all the open connections from the server end.
The default number of listeners is 10.
Adding the data
event listener to process.stdin
add a reference to it that keeps the process open. That reference stays in place even after removing all event listeners. What you can do is manually unref()
it in your callback, like so:
console.log('Press Enter to allow process to terminate')
process.stdin.once('data', callback)
function callback (data) {
console.log('Process can terminate now')
process.stdin.unref()
}
Also, as a general debugging tool for stuff like this, there are two (undocumented) functions that you can call to get a list of things keeping your process open:
process._getActiveHandles()
process._getActiveRequests()
See this pull request in the node project for background.
Update: You asked about attaching event listeners after you've unref()
'd process.stdin
. Here's a quick example showing that the listener does attach itself and function:
console.log('Press Enter to allow process to terminate')
process.stdin.once('data', callback)
function callback (data) {
console.log('Unreferencing stdin. Exiting in 5 seconds.')
process.stdin.unref()
process.stdin.once('data', function(data) {
console.log('More data')
})
setTimeout(function() {
console.log('Timeout, Exiting.')
}, 5000);
}
With that code, if you press another key before the setTimeout
fires (5 seconds), then you'll see More data
output to the console. Once the setTimeout
's callback fires, the process will exit. The trick is that setTimeout
is creating a timer which the process also keeps a reference too. Since the process still has a reference to something, it won't exit right away. Once the timer fires, the reference it released and the process exits. This also shows that references are added (and removed) to things that need them automatically (the timer created by setTimeout
in this case).
Just call .end
on the process.stdin
stream
To me, this is a more straightforward (and documented) way of ending the stream.
console.log('Press Enter to allow process to terminate');
process.stdin.once('data', callback);
function callback (data) {
console.log('Process can terminate now');
process.stdin.end();
}
It's also worth noting that node sets the stream as the context for the callback function, so you can just call this.end
console.log('Press Enter to allow process to terminate');
process.stdin.once('data', callback);
function callback (data) {
// `this` refers to process.stdin here
console.log('Process can terminate now');
this.end();
}
You could also emit an end
event which has additional benefits like being able to call a function when the stream is finished.
console.log('Press Enter to allow process to terminate');
process.stdin.once('data', function(data) {
console.log('Process can terminate now');
this.emit("end");
});
process.stdin.on('end', function() {
console.log("all done now");
});
This would output
Press Enter to allow process to terminate
Process can terminate now
all done now
A final solution would be to use process.exit
. This allows you to terminate a program whenver you want.
for (var i=0; i<10; i++) {
process.stdout.write( i.toString() );
if (i > 3) process.exit();
}
Output
01234
This would work inside of a stream callback, as part of a child process, or any other bit of code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With