通过 node 中的spawn()/exec()/...生成子进程时.js,在子进程上有一个'close'和一个'exit'事件.

这两者的区别是什么?什么时候需要使用什么?

推荐答案

在 node 之前.js 0.7.7中,子进程上只有一个"退出"事件(没有"关闭"事件).当子进程退出且所有流(stdin、stdout、stdout)关闭时,将触发此事件.

In Node 0.7.7,引入了"关闭"事件(see commit).

当子进程的stdio流关闭时,会发出"close"事件.这与"退出"事件不同,因为多个进程可能共享相同的stdio流.

如果你只是生成了一个程序,没有对stdio做任何特殊的操作,那么"退出"之后就会触发"关闭"事件.

因此,如果您只对进程终止感兴趣(例如,因为进程拥有独占资源),那么监听"退出"就足够了.

实验:在杀死子元素之前摧毁stdio

通过实验(在Node.js v7.2.0中),我发现如果子进程不使用stdio流,那么"close"事件只有在程序退出后才会触发:

// 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

类似地,当我修改生成一个只从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

Node.js相关问答推荐

从目录中获取所有文件,而不是NodeJS中的单个文件

购物车是空的状态|本地存储不更新产品数量|Redux|

如何将Node.js与Nuxt.js一起使用?

条件内的表达式

PM2 是否需要成为其托管项目的依赖项?

eSignature API 的 NodeJS SDK 是否支持数据流?

只要我在后端正确验证所有内容,就可以将这些数据存储在本地存储中吗?

为什么 client.on("messageCreate") 的 TextChannel 中缺少 nsfw 属性?

npm chokidar 触发事件两次

在新创建的 Angular 工作区上运行 ng lint 时出错

在 `DataFrame` 上使用用户定义的可链接函数抽象出 Polars 表达式

提供静态文件到底是什么意思?

适用于 Windows 的 NVM 无法正常工作?

运行摩卡+伊斯坦布尔+通天塔

Node.js:socket.io 关闭客户端连接

在 Node.js 中使用公钥加密数据

从 React(同构应用程序)进行 API 调用时出现Access-Control-Allow-Origin问题

node.js 在控制台上显示未定义

react-native run-android 无法识别

node.js 异步库