Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/421.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 为什么';删除所有侦听器后my Node.js进程是否终止?_Javascript_Node.js_Event Listener - Fatal编程技术网

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()
'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秒),您将看到
更多数据输出到控制台。一旦
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