Javascript 为什么';删除所有侦听器后my Node.js进程是否终止?
在下面的代码中,我使用Javascript 为什么';删除所有侦听器后my Node.js进程是否终止?,javascript,node.js,event-listener,Javascript,Node.js,Event Listener,在下面的代码中,我使用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') } 理论上,当启动回调时,应该自动删除事件侦听器(因为我用将其附加了一
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')
}
理论上,当启动回调时,应该自动删除事件侦听器(因为我用将其附加了一次),从而允许进程终止。令人惊讶的是,在这种情况下,进程从未终止(您看到的代码就是全部,请尝试!)。我还尝试手动删除侦听器,但没有任何改变
这里还有什么我不知道的吗?将数据事件侦听器添加到进程中。stdin
添加对它的引用以保持进程打开。即使在删除所有事件侦听器之后,该引用仍保持不变。您可以在回调中手动unref()
it,如下所示:
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()
有关背景信息,请参见节点项目中的
更新:您在unref()
'dprocess.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秒),您将看到更多数据输出到控制台。一旦setTimeout
的回调触发,进程将退出。诀窍在于setTimeout
正在创建一个计时器,该进程还保留一个引用。由于进程仍然有对某个对象的引用,因此它不会立即退出。一旦计时器触发,它将释放引用并退出进程。这也表明引用被自动添加(或删除)到需要它们的东西中(在本例中是由setTimeout
创建的计时器)。只需调用进程.stdin上的.end
对我来说,这是一种更直接(和)的结束流程的方法
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();
}
还值得注意的是,node将流设置为回调函数的上下文,因此您可以只调用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");
});
这将产生
按Enter键以允许进程终止
进程现在可以终止
现在都做完了
最终的解决方案是使用进程。退出。这允许您在需要时终止程序
for (var i=0; i<10; i++) {
process.stdout.write( i.toString() );
if (i > 3) process.exit();
}
这将在流回调内部工作,作为子进程的一部分,或任何其他代码位。选项太多了!但是对于其他看到这个答案的人,一定要检查Mike的答案,它也解释了为什么这是必要的,并给出了另一个选项。一旦我删除了引用,似乎我就不能再将事件侦听器附加到stdin了。尝试process.stdin.once('data',函数(d){console.log('logged');this.end();process.stdin.once('data',函数(d2){console.log('never logged')})。此日志记录“已记录”,然后等待我按Enter键。当我按Enter键时,进程终止。从技术上讲,添加了事件侦听器,它永远不会触发。在这种情况下,对process.stdin的引用是保持流程打开的唯一方法。手动删除后,进程将在当前运行循环结束时退出,因此您添加到的事件侦听器不可能启动。具有引用的对象在创建时将自动设置一个,因此,流程从引用process.stdin
开始,并保持其打开状态。我用一个示例更新了我的答案,显示在unref()
之后添加的事件侦听器仍然有效(只要有东西保持流程打开)。好吧,您只能unref()
process.stdin
,您不能ref()
请再试一次。因此,当您调用unref()
时,必须确保您已经完成了它。计时器的把戏就是这样,一个把戏;在大多数情况下我不会用那样的东西。如果您同时(异步)发生了一系列事情,并且需要等待它们全部完成,那么您可能需要查看类似于、或承诺的内容。使用这两种方法中的任何一种,您都可以在所有异步任务完成后获得回调;在那里你可以调用unref()
@naomik好吧,我不再把监听器附加到已完成的流中:p事实上,这个答案为我提供了我所缺乏的知识。实际上,我在代码中使用了end()
,而不是unref()
。我选择这个答案的原因是,除了说明如何解决问题外,它还解释了正在发生的事情。在这两种情况下,解决方案都是有效的,但在这种情况下,答案让我了解了为什么它两次都不起作用。有道理?
01234