在Node.js中通过spawn()/exec()/...
生成子进程时,子进程上会发生'close'
和'exit'
事件。
这两者之间有什么区别,什么时候需要使用什么?
答案 0 :(得分:24)
在Node.js 0.7.7之前,只有一个"退出"关于子进程的事件(并且没有"关闭"事件)。子进程退出时将触发此事件,并关闭所有流(stdin,stdout,stdout)。
In Node 0.7.7,"关闭"事件被引入(see commit)。 documentation (permalink)目前说:
'关闭'当子进程的stdio流已关闭时,将发出事件。这与退出'不同。事件,因为多个进程可能共享相同的stdio流。
如果你只是产生一个程序并且没有对stdio做任何特别的事情,那么"关闭"事件在"退出"之后触发。
"关闭"例如,如果事件延迟stdout流被传送到另一个流。这意味着"关闭"事件可以在"退出"之后延迟(无限期)事件。
这是否意味着"关闭"事件总是在"退出"?之后被解雇如下面的例子所示,答案是否定的。
因此,如果您只对流程终止感兴趣(例如,因为流程拥有独占资源),请监听"退出"足够了。 如果您不关心该计划,只关心其输入和/或输出,请使用"关闭"事件。
通过实验(在Node.js v7.2.0中),我发现如果子进程没有使用stdio流,那么"关闭"只有在程序退出后才会触发事件:
// The "sleep" command takes no input and gives no output.
cp = require('child_process').spawn('sleep', ['100']);
cp.on('exit', console.log.bind(console, 'exited'));
cp.on('close', console.log.bind(console, 'closed'));
cp.stdin.end();
cp.stdout.destroy();
cp.stderr.destroy();
console.log('Closed all stdio');
setTimeout(function() {
console.log('Going to kill');
cp.kill();
}, 500);
上述计划产生"睡眠"输出:
Closed all stdio
Going to kill
exited null SIGTERM
closed null SIGTERM
当我将第一行更改为仅输出的程序时,
// The "yes" command continuously outputs lines with "y"
cp = require('child_process').spawn('yes');
...然后输出是:
Closed all stdio
exited 1 null
closed 1 null
Going to kill
同样,当我更改spawn一个只从stdin读取的程序时,
// Keeps reading from stdin.
cp = require('child_process').spawn('node', ['-e', 'process.stdin.resume()']);
或者当我从stdin读取并输出到stdout时,
// "cat" without arguments reads from stdin, and outputs to stdout
cp = require('child_process').spawn('cat');
之前的实验非常人为。下一个实验更加现实:你将一个程序传送到另一个程序并杀掉第一个程序。
// Reads from stdin, output the input to stdout, repeat.
cp = require('child_process').spawn('bash', ['-c', 'while read x ; do echo "$x" ; done']);
cp.on('exit', console.log.bind(console, 'exited'));
cp.on('close', console.log.bind(console, 'closed'));
cpNext = require('child_process').spawn('cat');
cp.stdout.pipe(cpNext.stdin);
setTimeout(function() {
// Let's assume that it has started. Now kill it.
cp.kill();
console.log('Called kill()');
}, 500);
输出:
Called kill()
exited null SIGTERM
closed null SIGTERM
同样,当第一个程序只从输入读取而从不输出时:
// Keeps reading from stdin, never outputs.
cp = require('child_process').spawn('bash', ['-c', 'while read ; do : ; done']);
当第一个程序在不等待stdin的情况下继续输出时,行为会有所不同,如下一个实验所示。
// Equivalent to "yes | cat".
cp = require('child_process').spawn('yes');
cp.on('exit', console.log.bind(console, 'exited'));
cp.on('close', console.log.bind(console, 'closed'));
cpNext = require('child_process').spawn('cat');
cp.stdout.pipe(cpNext.stdin);
setTimeout(function() {
// Let's assume that it has started. Now kill it.
cp.kill();
console.log('Called kill()');
setTimeout(function() {
console.log('Expecting "exit" to have fired, and not "close"');
// cpNext.kill();
// ^ Triggers 'error' event, errno ECONNRESET.
// ^ and does not fire the 'close' event!
// cp.stdout.unpipe(cpNext.stdin);
// ^ Does not appear to have any effect.
// ^ calling cpNext.kill() throws ECONNRESET.
// ^ and does not fire the 'close' event!
cp.stdout.destroy(); // <-- triggers 'close'
cpNext.stdin.destroy();
// ^ Without this, cpNext.kill() throws ECONNRESET.
cpNext.kill();
}, 500);
}, 500);
上述程序输出以下内容然后退出:
Called kill()
exited null SIGTERM
Expecting "exit" to have fired, and not "close"
closed null SIGTERM
答案 1 :(得分:0)
你看过文档了吗?
根据this:
&#39;关闭&#39;当子进程的stdio流已关闭时,将发出事件。 这与&#39;退出&#39;不同。事件,因为多个进程可能共享相同的stdio流。
&#39;退出&#39;子进程结束后发出事件。如果进程退出,则代码是进程的最终退出代码,否则为null。如果由于接收到信号而终止该过程,则signal是信号的字符串名称,否则为null。其中一个永远不会为空。
答案 2 :(得分:0)
短版本是,'exit'在孩子退出但stdio 尚未关闭时发出。 当孩子退出并时,'close'会关闭。
除此之外,他们共享相同的签名。