为什么我的Node.js进程一旦所有的监听器都被删除就终止?
在下面的代码中,我使用once
方法为process.stdin
的data
事件分配了一个监听器。
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.stdin
stream上调用.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的一部分或其他任何代码。