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)的时候如何知道在什么时候退出运行?


3 回复

标题: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}`);
});

解释

  1. spawn 方法spawn 方法用于启动一个新的进程,并返回一个 ChildProcess 对象,该对象提供了与子进程交互的方法。
  2. pipe 方法:通过 pipe 方法将父进程的输入流连接到子进程的输入流,同时将子进程的输出流连接到父进程的输出流,这样可以确保数据能够正确地从父进程流向子进程,再从子进程流回父进程。
  3. 监听 exit 事件child.on('exit', ...) 用于监听子进程退出的事件。当子进程正常退出或因收到终止信号(如 SIGTERM 或 SIGINT)而退出时,该事件会被触发。事件回调函数接收两个参数:退出码 (code) 和退出信号 (signal)。
  4. 监听 error 事件child.on('error', ...) 用于监听子进程执行过程中可能出现的任何错误。

总结

通过监听 child_processexit 事件,你可以轻松得知子进程何时退出。这使得你可以在子进程退出后执行必要的清理工作或通知用户。注意,process.exit(0) 并不是必须的,Node.js 会自动处理子进程的退出状态。


发现可以通过设置stdio选项为inherit来实现,顺带翻译了一下文档

child_process.spawn() 中的 stdio 选项是一个数组,每个索引对应子进程中的一个文件标识符。可以是下列值之一:

  1. 'pipe' -在子进程与父进程之间创建一个管道,管道的父进程端以 child_process 的属性的形式暴露给父进程,如 ChildProcess.stdio[fd]。 为 文件标识(fds) 0 - 2 建立的管道也可以通过 ChildProcess.stdin,ChildProcess.stdout 及 ChildProcess.stderr 分别访问。

  2. 'ipc' - 创建一个IPC通道以在父进程与子进程之间传递 消息/文件标识符。一个子进程只能有最多一个 IPC stdio 文件标识。 设置该选项激活 ChildProcess.send() 方法。如果子进程向此文件标识符写JSON消息,则会触发 ChildProcess.on(“message”)。 如果子进程是一个nodejs程序,那么IPC通道的存在会激活process.send()和process.on(‘message’)

  3. 'ignore' - 不在子进程中设置该文件标识。注意,Node 总是会为其spawn的进程打开 文件标识(fd) 0 - 2。 当其中任意一项被 ignored,node 会打开 /dev/null 并将其附给子进程的文件标识(fd)。

  4. Stream 对象 - 与子进程共享一个与tty,文件,socket,或者管道(pipe)相关的可读或可写流。 该流底层(underlying)的文件标识在子进程中被复制给stdio数组索引对应的文件标识(fd)

  5. 正数 - 该整形值被解释为父进程中打开的文件标识符。他与子进程共享,和Stream被共享的方式相似。

  6. 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_processexit 事件来得知子进程何时退出。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 事件也会被触发。

回到顶部