Nodejs 如何得知child_process退出
Nodejs 如何得知child_process退出
就是如果我希望通过自己的程序去调用npm init
这样的进程
这就需要把自己和子进程之间的输入输出做一下pipe
process.stdin.pipe(child.stdin);
child.stdout.pipe(process.stdout);
其他方面都没问题,但是我如何知道npm init
退出了呢?
目前的情况是进行到 Is this ok? (yes)
, 我敲回车之后,没有任何的事件被检测到了
我自己写了个简单的例子,用同样的方法去操作
var prompt = require('prompt');
prompt.start();
prompt.get(['username', 'email'], function (err, result) {
console.log('Command-line input received:');
console.log(' username: ' + result.username);
console.log(' email: ' + result.email);
process.exit(0);
});
这里,如果不执行process.exit(0)
,就会像刚才一样无法探测到。
而有了这句的话,我就可以
child.stdout.on('end', function() {});
或者
child.on('exit',function(){});
来得知
从而在袭击的程序中调用process.exit()
退出。
是不是有什么机制我不知道的?或者,node本身在没有process.exit(0)
的时候如何知道在什么时候退出运行?
标题:Node.js 如何得知 child_process 退出
内容:
在 Node.js 中使用 child_process
模块来启动和管理子进程是很常见的需求。例如,你可能希望调用 npm init
这样的命令。在这种情况下,你需要处理子进程的输入输出流,并且了解如何得知子进程何时退出。
示例代码
假设我们有一个场景,需要启动一个子进程来执行 npm init
命令,并在子进程结束时打印一条消息:
const { spawn } = require('child_process');
// 启动子进程
const child = spawn('npm', ['init']);
// 将父进程的标准输入管道连接到子进程的标准输入
process.stdin.pipe(child.stdin);
// 监听子进程的标准输出并将其输出到父进程的标准输出
child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr);
// 监听子进程的退出事件
child.on('exit', (code, signal) => {
console.log(`子进程退出,退出码: ${code}, 退出信号: ${signal}`);
});
// 如果有错误发生,监听错误事件
child.on('error', (err) => {
console.error(`子进程执行出错: ${err.message}`);
});
解释
- spawn 方法:
spawn
方法用于启动一个新的进程,并返回一个ChildProcess
对象,该对象提供了与子进程交互的方法。 - pipe 方法:通过
pipe
方法将父进程的输入流连接到子进程的输入流,同时将子进程的输出流连接到父进程的输出流,这样可以确保数据能够正确地从父进程流向子进程,再从子进程流回父进程。 - 监听 exit 事件:
child.on('exit', ...)
用于监听子进程退出的事件。当子进程正常退出或因收到终止信号(如 SIGTERM 或 SIGINT)而退出时,该事件会被触发。事件回调函数接收两个参数:退出码 (code
) 和退出信号 (signal
)。 - 监听 error 事件:
child.on('error', ...)
用于监听子进程执行过程中可能出现的任何错误。
总结
通过监听 child_process
的 exit
事件,你可以轻松得知子进程何时退出。这使得你可以在子进程退出后执行必要的清理工作或通知用户。注意,process.exit(0)
并不是必须的,Node.js 会自动处理子进程的退出状态。
发现可以通过设置stdio选项为inherit来实现,顺带翻译了一下文档
child_process.spawn()
中的 stdio
选项是一个数组,每个索引对应子进程中的一个文件标识符。可以是下列值之一:
-
'pipe'
-在子进程与父进程之间创建一个管道,管道的父进程端以child_process
的属性的形式暴露给父进程,如ChildProcess.stdio[fd]
。 为 文件标识(fds) 0 - 2 建立的管道也可以通过 ChildProcess.stdin,ChildProcess.stdout 及 ChildProcess.stderr 分别访问。 -
'ipc'
- 创建一个IPC通道以在父进程与子进程之间传递 消息/文件标识符。一个子进程只能有最多一个 IPC stdio 文件标识。 设置该选项激活 ChildProcess.send() 方法。如果子进程向此文件标识符写JSON消息,则会触发 ChildProcess.on(“message”)。 如果子进程是一个nodejs程序,那么IPC通道的存在会激活process.send()和process.on(‘message’) -
'ignore'
- 不在子进程中设置该文件标识。注意,Node 总是会为其spawn的进程打开 文件标识(fd) 0 - 2。 当其中任意一项被 ignored,node 会打开/dev/null
并将其附给子进程的文件标识(fd)。 -
Stream
对象 - 与子进程共享一个与tty,文件,socket,或者管道(pipe)相关的可读或可写流。 该流底层(underlying)的文件标识在子进程中被复制给stdio数组索引对应的文件标识(fd) -
正数 - 该整形值被解释为父进程中打开的文件标识符。他与子进程共享,和
Stream
被共享的方式相似。 -
null
,undefined
- 使用默认值。 对于stdio fds 0,1,2(或者说stdin,stdout和stderr),pipe管道被建立。对于fd 3及往后,默认为ignore
按照文档的意思,默认情况下,stdio的值为 [‘pipe’,‘pipe’,‘pipe’],作用就是让父进程可以拿到子进程的stdin,stdout,stderr,但具体作何操作,看具体需求。
如果是ignore,就拿不到这几对象。
而如果传Stream,则会在把子进程中的流复制给父进程达到同步的效果 (The stream’s underlying file descriptor is duplicated in the child process to the fd that corresponds to the index in the stdio
array.)
不过我还是不太理解单纯的pipe与用stdio传递Stream当中有什么细微的差别。
你可以通过监听 child_process
的 exit
事件来得知子进程何时退出。Node.js 提供了一个非常方便的方法来处理这种场景。
以下是使用 child_process.spawn()
或 child_process.exec()
创建子进程,并监听 exit
事件的示例:
const { spawn } = require('child_process');
// 创建一个子进程
const child = spawn('npm', ['init']);
// 将标准输入和输出流进行管道传输
process.stdin.pipe(child.stdin);
child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr);
// 监听子进程退出事件
child.on('exit', (code, signal) => {
console.log(`子进程退出,退出码为 ${code},退出信号为 ${signal}`);
});
// 如果希望在某个条件满足时退出子进程
// 可以监听标准输出或标准错误流的 'data' 事件
child.stdout.on('data', (data) => {
const output = data.toString();
if (output.includes('Is this ok')) {
child.stdin.write('yes\n'); // 输入 'yes'
}
// 在这里可以添加更多逻辑来决定是否退出子进程
});
在这个例子中,我们创建了一个子进程来运行 npm init
命令。我们将父进程的标准输入、标准输出和标准错误分别连接到子进程的标准输入、标准输出和标准错误。这样,我们可以将用户输入传递给子进程,并将子进程的输出显示给用户。
我们通过 child.on('exit', ...)
来监听子进程的退出事件。当子进程退出时,exit
事件会被触发,我们可以在回调函数中处理相应的逻辑,比如记录退出码或信号。
如果你不调用 process.exit()
,Node.js 会在所有事件监听器都处理完毕后自动退出。在这种情况下,exit
事件也会被触发。