在以下代码中,我使用data
方法为process.stdin
once
事件分配了一个监听器。
console.log('Press Enter to allow process to terminate')
process.stdin.once('data', callback)
function callback (data) {
console.log('Process can terminate now')
}
理论上,当回调被触发时,应该自动删除事件监听器(因为我用once
附加了它),允许进程终止。令人惊讶的是,在这种情况下,进程永远不会终止(你看到的代码就是整个东西,试试吧!)。我也试过手动删除监听器,但这没有任何改变。
这里还有其他事情我也许没有意识到吗?
答案 0 :(得分:25)
将data
事件侦听器添加到process.stdin
添加对该进程保持打开状态的引用。即使在删除所有事件侦听器之后,该引用也会保留。您可以做的是在回调中手动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()
}
此外,作为此类内容的一般调试工具,您可以调用两个(未记录的)函数来获取保持流程开放的事项列表:
process._getActiveHandles()
process._getActiveRequests()
请参阅节点项目中的this pull request了解背景信息。
更新:您询问了在unref()
' d 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
的回调触发,该过程将退出。诀窍是setTimeout
正在创建一个计时器,该进程也会保留一个引用。由于该过程仍然提及某些内容,因此它不会立即退出。一旦计时器触发,它就会释放引用并退出进程。这也表明引用被添加(和删除)到自动需要的东西(在这种情况下由setTimeout
创建的计时器)。
答案 1 :(得分:9)
只需在.end
信息流
process.stdin
即可
对我而言,这是一种更直接(和documented)结束流的方式。
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();
}
还值得注意的是,节点将流设置为回调函数的上下文,因此您只需调用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
事件,该事件具有额外的好处,例如在流完成时能够调用函数。
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
最终的解决方案是使用process.exit
。这允许您随时终止程序。
for (var i=0; i<10; i++) {
process.stdout.write( i.toString() );
if (i > 3) process.exit();
}
输出
01234
这可以在流回调中工作,作为子进程的一部分,或任何其他代码。