我使用spawn
来创建子进程和管道数据:
child process | parent process (main)
---------------------------------------
stdout -----> process.stdout
stderr -----> process.stderr
stdin <----- process.stdin
问题是,当process.stdin
管道到子进程stdin
时,当子进程结束时,主进程没有结束。
代码看起来像这样(不是一个很好的例子,因为ps
不使用stdin
数据,我猜):
var Spawn = require("child_process").spawn;
var ps = Spawn("ps");
process.stdin.pipe(ps.stdin);
ps.stdout.pipe(process.stdout);
ps.stderr.pipe(process.stderr);
如果我删除process.stdin.pipe(ps.stdin)
行,主进程结束,但stdin
数据不再是管道。
为什么ps
子进程结束时主进程没有结束?我该如何解决这个问题?
一个丑陋的解决方案是:
ps.on("close", process.exit.bind(process));
我不喜欢这个,因为我真的不想强迫主进程关闭,但我想自然地关闭(例如让setTimeout(function(){}, 1000)
等待1000ms,然后进程结束)。
我不知道这是Node中的错误还是预期的行为,但是有几个解决方法,其中一个可能适合您。
如果当前进程恰好在子进程结束时结束,您可以简单地为exit
添加一个处理程序,如下所示:
const fail = err => { throw err }
ps.on("exit", (code, signal) => code !== null ? process.exit(code) : signal !== null ? process.kill(process.pid, signal) : fail("Impossible situation, child process neither exited nor was killed"))
这将绕过我们的问题,stdin
流坐在那里阻止一切。
如果你需要在当前进程中做更多的事情,而不仅仅是运行这个子进程,这种方法可能是不可接受的。当你意识到当前流程应该做的所有工作都已经完成时,你可以做的是destroy
process.stdin
。例如,如果您只希望运行ps
,则可以添加:
ps.on("exit", (...) => {
...
process.stdin.destroy()
})
,这将有相同的效果。如果在ps
死后需要做更多的工作,可以将相同的事情放在其他适当的事件处理程序中。