为什么我的Node.js进程一旦所有的监听器都被删除就终止?

在下面的代码中,我使用once方法为process.stdindata事件分配了一个监听器。

 console.log('Press Enter to allow process to terminate') process.stdin.once('data', callback) function callback (data) { console.log('Process can terminate now') } 

理论上,当callback触发时,事件侦听器应该被自动删除(因为我附加了once ),允许进程终止。 令人惊讶的是,在这种情况下,这个过程永远不会终止(你看到的代码是完整的,试试吧!)。 我也尝试手动删除侦听器,但这并没有改变。

或许还有别的事情发生在我身上?

data事件侦听器添加到process.stdin添加一个引用来保持进程打开。 即使在删除所有事件侦听器之后,该引用仍然保留。 你可以做的是在你的callback函数中手动unref()它,如下所示:

 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() } 

另外,作为一个像这样的东西的一般debugging工具,有两个(未logging的)函数,您可以调用以获取保持您的进程打开的东西的列表:

 process._getActiveHandles() process._getActiveRequests() 

在节点项目中查看此拉取请求的背景。


更新:在你有了unref() ' process.stdin之后,你问到附加事件监听器了。 下面是一个简单的示例,显示监听器将自己附加到函数中:

 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); } 

使用该代码,如果在setTimeout触发(5秒)之前按另一个键,则会看到More data输出到控制台。 一旦setTimeout的callback触发,该过程将退出。 诀窍是setTimeout正在创build一个计时器,该进程也保持参考。 由于该过程仍然有一些参考,它不会马上退出。 一旦定时器启动,它释放的引用和进程退出。 这也表明引用被添加(和删除)到自动需要的东西(在这种情况下由setTimeout创build的定时器)。

只需在process.stdinstream上调用.end

对我来说,这是一个更直接的(和logging )结束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(); } 

还值得注意的是,节点将stream设置为callback函数的上下文,因此您可以调用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(); } 

您还可以发出一个end事件,它具有额外的好处,例如可以在stream完成时调用一个函数。

 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"); }); 

这将输出

 Press Enter to allow process to terminate Process can terminate now all done now 

最终的解决scheme是使用process.exit 。 这使您可以随时终止程序。

 for (var i=0; i<10; i++) { process.stdout.write( i.toString() ); if (i > 3) process.exit(); } 

产量

 01234 

这可以在streamcallback中使用,作为subprocess的一部分或其他任何代码。