Javascript 回复子进程中的消息

Javascript 回复子进程中的消息,javascript,node.js,Javascript,Node.js,我正在寻找一种有效的方式来回复发送给子进程的消息。目前,我正在使用以下代码: const { fork } = require('child_process'); const child = fork(path.join(__dirname, 'sub.js')); async function run() { console.log('Requesting status....'); child.send('status'); const status = await

我正在寻找一种有效的方式来回复发送给子进程的消息。目前,我正在使用以下代码:

 const { fork } = require('child_process');
 const child = fork(path.join(__dirname, 'sub.js'));

 async function run() {
   console.log('Requesting status....');
   child.send('status');
   const status = await awaitMessage(child);
   console.log(status);
 }

 function awaitMessage(childProcess) {
   return new Promise((resolve) => {
     childProcess.on('message', (m) => {
       resolve(m);
     });
   });
 }
此代码的问题在于,每次调用
awaitMessage()
函数时,它都会创建一个新的事件侦听器,这很容易导致内存泄漏。是否有一种优雅的方式来接收子进程的回复?

这并不是真的“容易发生内存泄漏”,因为泄漏是应该被释放的(根据垃圾收集器的规则),但不是。在本例中,您留下了一个连接到事件处理程序的承诺,该事件处理程序仍然可以被调用,因此系统无法知道您打算释放它

因此,系统保留的正是代码要求它保留的内容。您的代码工作方式的结果是,它保留了在
awaitMessage()
中创建的所有承诺,还触发了一系列额外的事件处理程序。因为您保留了事件侦听器,所以垃圾收集器看到该侦听器仍然可以“访问”承诺,因此即使没有外部引用,也不能也不应该删除该承诺(根据Javascript垃圾收集器的规则)

如果要在承诺中添加事件侦听器,则必须在承诺解析时删除该事件侦听器,以便最终释放该承诺。promise在Javascript中不是神奇的对象,它只是一个常规对象,所以只要您有一个可以被实时事件侦听器引用的对象,该对象就不能被垃圾收集

此外,如果您连续两次调用
awaitMessage()
,则这取决于竞争条件,因为这两个承诺都将响应下一条消息。一般来说,这不是一个好的设计方法。如果您想等待消息,那么您必须以某种方式标记消息,以便知道您正在等待的消息响应是哪个消息响应,以避免竞争条件,并且在收到消息后必须删除事件侦听器

要避免由于侦听器的累积而导致内存累积,可以执行以下操作:

 function awaitMessage(childProcess) {
   return new Promise((resolve) => {
     function handleMsg(m) {
       childProcess.removeListener(handleMsg);
       resolve(m);
     }
     childProcess.on('message', handleMsg);
   });
 }

为什么这样容易出现内存泄漏?一旦实例不再被引用(返回时),它就会被释放。根据子进程返回所需的时间,可能会同时打开几十个事件侦听器。几十个似乎不是问题。最终,您希望在一个池中管理它们。这就是大多数情况下线程的管理和包含方式。添加了删除侦听器以允许GCD承诺的代码示例。@JohnLandon-这是否回答了您的问题?