Node.js v18.18.2 文档


目录

子进程#

稳定性:2 - 稳定

源代码: lib/child_process.js

node:child_process模块提供了以与popen(3)类似但不相同的方式生成子进程的能力。此功能主要由child_process.spawn()函数提供:

const { spawn } = require('node:child_process');
const ls = spawn('ls', ['-lh', '/usr']);

ls.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

ls.stderr.on('data', (data) => {
  console.error(`stderr: ${data}`);
});

ls.on('close', (code) => {
  console.log(`child process exited with code ${code}`);
}); 

默认情况下,在父 Node.js 进程和生成的子进程之间建立stdinstdoutstderr 的管道。这些管道的容量有限(且特定于平台)。如果子进程写入 stdout 的次数超过该限制而未捕获输出,则子进程会阻塞等待管道缓冲区接受更多数据。这与Shell中管道的行为相同。 如果不消耗输出,请使用{ stdio: 'ignore' }选项。

如果env位于options对象中,则使用 options.env.PATH 环境变量执行命令查找。否则,使用process.env.PATH 。如果设置了options.env而不设置PATH,则 Unix 上的查找将在默认搜索路径搜索/usr/bin:/bin上执行(请参阅操作系统的 execvpe/execvp 手册),在 Windows 上,使用当前进程环境变量PATH

在 Windows 上,环境变量不区分大小写。Node.js 按字典顺序对env键进行排序,并使用第一个不区分大小写匹配的键。只有第一个(按字典顺序)条目才会传递到子流程。当将对象传递给具有同一键的多个变体(例如 PATHPathenv选项时,这可能会导致 Windows 上出现问题。

child_process.spawn()方法异步生成子进程,不会阻塞 Node.js 事件循环。child_process.spawnSync()函数 以同步方式提供等效功能,阻止事件循环,直到生成的进程退出或终止。

为了方便起见,node:child_process模块提供了一些child_process.spawn()child_process.spawnSync()的同步和异步替代方案。这些替代方案都是在child_process.spawn()child_process.spawnSync()之上实现的。

对于某些用例,例如自动化 shell 脚本, 同步对应项可能更方便。然而,在许多情况下,同步方法可能会对性能产生重大影响,因为在生成的进程完成时会停止事件循环。

异步流程创建#

child_process.spawn()child_process.fork()child_process.exec()child_process.execFile()方法都遵循其他 Node.js API 典型的惯用异步编程模式。

每个方法都会返回一个ChildProcess实例。这些对象实现 Node.js EventEmitter API,允许父进程注册侦听器函数,这些函数在子进程生命周期中发生某些事件时调用。

child_process.exec()child_process.execFile()方法还允许指定一个可选的callback函数,该函数在子进程终止时调用。

在 Windows 上生成.bat.cmd文件#

child_process.exec()child_process.execFile()之间的区别重要性可能因平台而异。在 Unix 类型操作系统(Unix、Linux、macOS)上,child_process.execFile()可能会更高效,因为它默认情况下不会生成 shell。但是,在 Windows 上,.bat.cmd文件在没有终端的情况下无法自行执行,因此无法使用child_process.execFile()启动。在 Windows 上运行时,可以使用设置了 shell 选项 的 child_process.spawn()child_process.exec(),或者通过生成cmd.exe并传递.bat.cmd文件作为参数(这就是shell选项和 child_process.exec()做)。无论如何,如果脚本文件名包含空格,则需要用引号引起来。

// On Windows Only...
const { spawn } = require('node:child_process');
const bat = spawn('cmd.exe', ['/c', 'my.bat']);

bat.stdout.on('data', (data) => {
  console.log(data.toString());
});

bat.stderr.on('data', (data) => {
  console.error(data.toString());
});

bat.on('exit', (code) => {
  console.log(`Child exited with code ${code}`);
}); 
// OR...
const { exec, spawn } = require('node:child_process');
exec('my.bat', (err, stdout, stderr) => {
  if (err) {
    console.error(err);
    return;
  }
  console.log(stdout);
});

// Script with spaces in the filename:
const bat = spawn('"my script.cmd"', ['a', 'b'], { shell: true });
// or:
exec('"my script.cmd" a b', (err, stdout, stderr) => {
  // ...
}); 

child_process.exec(command[, options][, callback])#

生成一个 shell,然后在该 shell 中执行command ,缓冲任何生成的输出。传递给 exec 函数的command字符串由 shell 直接处理,特殊字符(根据 shell不同)需要进行相应处理:

const { exec } = require('node:child_process');

exec('"/path/to/test file/test.sh" arg1 arg2');
// Double quotes are used so that the space in the path is not interpreted as
// a delimiter of multiple arguments.

exec('echo "The \\$HOME variable is $HOME"');
// The $HOME variable is escaped in the first instance, but not in the second. 

切勿将未经处理的用户输入传递给此函数。任何包含 shell 元字符的输入都可用于触发任意命令执行。

如果提供了callback函数,则使用参数 (error, stdout, stderr)调用它。成功后,error将是null。出错时, error将是Error的实例。error.code属性将是进程的退出代码。按照约定,除0之外的任何退出代码都 表示错误。error.signal将是终止进程的信号。

传递给回调的stdoutstderr参数将包含子进程的 stdout 和 stderr 输出。默认情况下,Node.js 会将输出解码为 UTF-8 并将字符串传递给回调。encoding选项可用于指定用于解码 stdout 和 stderr 输出的字符编码。如果encoding'buffer'或无法识别的字符编码,则Buffer对象将被传递给回调。

const { exec } = require('node:child_process');
exec('cat *.js missing_file | wc -l', (error, stdout, stderr) => {
  if (error) {
    console.error(`exec error: ${error}`);
    return;
  }
  console.log(`stdout: ${stdout}`);
  console.error(`stderr: ${stderr}`);
}); 

如果timeout大于0 ,则父级将发送由killSignal属性标识的信号(默认为'SIGTERM')子进程运行时间超过timeout毫秒。

exec(3) POSIX 系统调用不同,child_process.exec()不会替换现有进程,而是使用 shell 来执行命令。

如果此方法作为其util.promisify() ed 版本调用,它将返回一个Promise ,其中包含stdoutstderr特性。返回的 ChildProcess实例作为child属性附加到Promise。如果发生错误(包括导致退出代码不为 0 的任何错误),则会返回被拒绝的 Promise,并在回调中提供相同的 error对象,但具有两个附加属性stdoutstderr

const util = require('node:util');
const exec = util.promisify(require('node:child_process').exec);

async function lsExample() {
  const { stdout, stderr } = await exec('ls');
  console.log('stdout:', stdout);
  console.error('stderr:', stderr);
}
lsExample(); 

如果启用了signal选项,则在相应的 AbortController上调用.abort()与在子进程上调用.kill()类似,只是传递了错误回调将是一个AbortError

const { exec } = require('node:child_process');
const controller = new AbortController();
const { signal } = controller;
const child = exec('grep ssh', { signal }, (error) => {
  console.error(error); // an AbortError
});
controller.abort(); 

child_process.execFile(file[, args][, options][, callback])#

child_process.execFile()函数与child_process.exec()类似 ,只是它默认不生成 shell。相反,指定的可执行文件file直接作为新进程生成,使其比child_process.exec()效率稍高。

支持与child_process.exec()相同的选项。由于未生成 shell,因此不支持 I/O 重定向和文件通配等行为。

const { execFile } = require('node:child_process');
const child = execFile('node', ['--version'], (error, stdout, stderr) => {
  if (error) {
    throw error;
  }
  console.log(stdout);
}); 

传递给回调的stdoutstderr参数将包含子进程的 stdout 和 stderr 输出。默认情况下,Node.js 会将输出解码为 UTF-8 并将字符串传递给回调。encoding选项可用于指定用于解码 stdout 和 stderr 输出的字符编码。如果encoding'buffer'或无法识别的字符编码,则Buffer对象将被传递给回调。

如果此方法作为其util.promisify() ed 版本调用,它将返回一个Promise,其中包含stdoutstderr特性。返回的 ChildProcess实例作为child属性附加到Promise。如果发生错误(包括导致退出代码不为 0 的任何错误),则会返回被拒绝的 Promise,并在回调中给出相同的 error对象,但具有两个附加属性stdoutstderr

const util = require('node:util');
const execFile = util.promisify(require('node:child_process').execFile);
async function getVersion() {
  const { stdout } = await execFile('node', ['--version']);
  console.log(stdout);
}
getVersion(); 

如果启用了shell选项,请勿将未经处理的用户输入传递给此函数。任何包含 shell 元字符的输入都可用于触发任意命令执行。

如果启用了signal选项,则在相应的 AbortController上调用.abort()与在子进程上调用.kill()类似,只是传递了错误回调将是一个AbortError

const { execFile } = require('node:child_process');
const controller = new AbortController();
const { signal } = controller;
const child = execFile('node', ['--version'], { signal }, (error) => {
  console.error(error); // an AbortError
});
controller.abort(); 

child_process.fork(modulePath[, args][, options])#

  • modulePath <字符串> | <URL>要在子级中运行的模块。
  • args <string[]>字符串参数列表。
  • options <对象>
    • cwd <字符串> | <URL>子进程的当前工作目录。
    • detached <boolean>准备子进程独立于其父进程运行。具体行为取决于平台,请参阅 options.detached)。
    • env <Object>环境键值对。默认值: process.env
    • execPath <string>用于创建子进程的可执行文件。
    • execArgv <string[]>传递给可执行文件的字符串参数列表。 默认值: process.execArgv
    • gid <number>设置进程的组标识(请参阅setgid(2))。
    • serialization <string>指定用于在进程之间发送消息的序列化类型。可能的值为'json''advanced'。有关更多详细信息,请参阅高级序列化默认值: 'json'
    • signal <AbortSignal>允许使用 AbortSignal 关闭子进程。
    • killSignal <字符串> | <integer>当生成的进程因超时或中止信号而终止时要使用的信号值。默认值: 'SIGTERM'
    • silent <boolean>如果true,子级的 stdin、stdout 和 stderr 将通过管道传输到父级,否则它们将从父级继承,请参阅 'pipe'有关更多详细信息,请参阅 child_process.spawn()stdio的 和'inherit'选项。默认值:false
    • stdio <数组> | <string>请参阅child_process.spawn()stdio。当提供此选项时,它将覆盖silent。如果使用数组变体,则它必须恰好包含一项值为'ipc'的项目,否则将引发错误。例如[0, 1, 2, 'ipc']
    • uid <number>设置进程的用户身份(请参阅setuid(2))。
    • windowsVerbatimArguments <boolean> Windows 上不会对参数进行引用或转义。在 Unix 上被忽略。默认值: false
    • timeout <number>允许进程运行的最长时间(以毫秒为单位)。默认值: undefined
  • 返回:<子进程>

child_process.fork()方法是child_process.spawn()的特例 ,专门用于生成新的 Node.js 进程。child_process.spawn()类似,返回一个ChildProcess对象。返回的ChildProcess将有一个额外的内置通信通道,允许消息在父级和子级之间来回传递。有关详细信息,请参阅subprocess.send()

请记住,生成的 Node.js 子进程独立于父进程,但两者之间建立的 IPC 通信通道除外。每个进程都有自己的内存和自己的 V8 实例。由于需要额外的资源分配,因此不建议生成大量 Node.js 子进程。

默认情况下,child_process.fork()将使用父进程的process.execPath生成新的 Node.js 实例 。options 对象中的 execPath属性允许使用替代执行路径。

使用自定义execPath启动的 Node.js 进程将使用子进程上的环境变量NODE_CHANNEL_FD标识的文件描述符 (fd) 与父进程通信。

fork(2) POSIX 系统调用不同,child_process.fork()不会克隆当前进程。

child_process.spawn()中可用的shell选项不受 child_process.fork()支持,如果设置,将被忽略。

如果启用了signal选项,则在相应的 AbortController上调用.abort()与在子进程上调用.kill()类似,只是传递了错误回调将是一个AbortError

if (process.argv[2] === 'child') {
  setTimeout(() => {
    console.log(`Hello from ${process.argv[2]}!`);
  }, 1_000);
} else {
  const { fork } = require('node:child_process');
  const controller = new AbortController();
  const { signal } = controller;
  const child = fork(__filename, ['child'], { signal });
  child.on('error', (err) => {
    // This will be called with err being an AbortError if the controller aborts
  });
  controller.abort(); // Stops the child process
} 

child_process.spawn(command[, args][, options])#

  • command <string>要运行的命令。
  • args <string[]>字符串参数列表。
  • options <对象>
    • cwd <字符串> | <URL>子进程的当前工作目录。
    • env <Object>环境键值对。默认值: process.env
    • argv0 <string>显式设置发送到子进程的argv[0]的值。如果未指定,这将设置为command
    • stdio <数组> | <string>子级的 stdio 配置(请参阅 options.stdio)。
    • detached <boolean>准备子进程独立于其父进程运行。具体行为取决于平台,请参阅 options.detached)。
    • uid <number>设置进程的用户身份(请参阅setuid(2))。
    • gid <number>设置进程的组标识(请参阅setgid(2))。
    • serialization <string>指定用于在进程之间发送消息的序列化类型。可能的值为'json''advanced'。有关更多详细信息,请参阅高级序列化默认值: 'json'
    • shell <布尔值> | <string>如果true,则在 shell 内运行command 。在 Unix 上使用 '/bin/sh',在 Windows 上使用process.env.ComSpec 。可以将不同的 shell 指定为字符串。请参阅Shell 要求默认 Windows shell默认值: false(无 shell)。
    • windowsVerbatimArguments <boolean> Windows 上不会对参数进行引用或转义。在 Unix 上被忽略。当指定shell且为 CMD时,此值会自动设置为true默认值: false
    • windowsHide <boolean>隐藏通常在 Windows 系统上创建的子进程控制台窗口。默认值: false
    • signal <AbortSignal>允许使用 AbortSignal 中止子进程。
    • timeout <number>允许进程运行的最长时间(以毫秒为单位)。默认值: undefined
    • killSignal <字符串> | <integer>当生成的进程因超时或中止信号而终止时要使用的信号值。默认值: 'SIGTERM'
  • 返回:<子进程>

child_process.spawn()方法使用给定的command生成一个新进程 ,并在args中使用命令行参数。如果省略,则args默认为空数组。

如果启用了shell选项,请勿将未经处理的用户输入传递给此函数。任何包含 shell 元字符的输入都可用于触发任意命令执行。

第三个参数可用于指定其他选项,默认值如下:

const defaults = {
  cwd: undefined,
  env: process.env,
}; 

使用cwd指定生成进程的工作目录。如果没有给出,则默认继承当前工作目录。如果给定,但路径不存在,则子进程会发出ENOENT错误并立即退出。当命令不存在时,也会发出ENOENT

使用env指定新进程可见的环境变量,默认为process.env

env 中的 undefined值将被忽略。

运行ls -lh /usr、捕获stdoutstderr和退出代码的示例:

const { spawn } = require('node:child_process');
const ls = spawn('ls', ['-lh', '/usr']);

ls.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

ls.stderr.on('data', (data) => {
  console.error(`stderr: ${data}`);
});

ls.on('close', (code) => {
  console.log(`child process exited with code ${code}`);
}); 

示例:运行ps ax | grep ssh 的一种非常复杂的方法

const { spawn } = require('node:child_process');
const ps = spawn('ps', ['ax']);
const grep = spawn('grep', ['ssh']);

ps.stdout.on('data', (data) => {
  grep.stdin.write(data);
});

ps.stderr.on('data', (data) => {
  console.error(`ps stderr: ${data}`);
});

ps.on('close', (code) => {
  if (code !== 0) {
    console.log(`ps process exited with code ${code}`);
  }
  grep.stdin.end();
});

grep.stdout.on('data', (data) => {
  console.log(data.toString());
});

grep.stderr.on('data', (data) => {
  console.error(`grep stderr: ${data}`);
});

grep.on('close', (code) => {
  if (code !== 0) {
    console.log(`grep process exited with code ${code}`);
  }
}); 

检查失败的spawn的示例:

const { spawn } = require('node:child_process');
const subprocess = spawn('bad_command');

subprocess.on('error', (err) => {
  console.error('Failed to start subprocess.');
}); 

某些平台(macOS、Linux)将使用argv[0]的值作为进程标题,而其他平台(Windows、SunOS)将使用command

Node.js在启动时会用process.execPath覆盖argv[0],因此 Node.js 子进程中的process.argv[0]将与传递的argv0 参数不匹配从家长处发送至spawn 。请改为使用process.argv0属性检索它 。

如果启用了signal选项,则在相应的 AbortController上调用.abort()与在子进程上调用.kill()类似,只是传递的错误不同回调将是一个AbortError

const { spawn } = require('node:child_process');
const controller = new AbortController();
const { signal } = controller;
const grep = spawn('grep', ['ssh'], { signal });
grep.on('error', (err) => {
  // This will be called with err being an AbortError if the controller aborts
});
controller.abort(); // Stops the child process 
options.detached#

在 Windows 上,将options.detached设置为true可以使子进程在父进程退出后继续运行。子进程将有自己的控制台窗口。子进程一旦启用,就无法禁用。

在非 Windows 平台上,如果options.detached设置为true,则子进程将成为新进程组和会话的领导者。子进程可以在父进程退出后继续运行,无论它们是否分离。请参阅setsid(2)了解更多信息。

默认情况下,父进程将等待分离的子进程退出。要防止父级等待给定的subprocess退出,请使用 subprocess.unref()方法。这样做将导致父级的事件循环不将子级包含在其引用计数中,从而允许父级独立于子级退出,除非子级和父级之间已建立 IPC 通道。

当使用detached选项启动长时间运行的进程时,该进程在父进程退出后不会在后台继续运行,除非它提供了未连接的stdio配置给家长。如果父级的stdio被继承,则子级将保持连接到控制终端。

长时间运行的进程的示例,通过分离并忽略其父 stdio文件描述符,以便忽略父进程的终止:

const { spawn } = require('node:child_process');

const subprocess = spawn(process.argv[0], ['child_program.js'], {
  detached: true,
  stdio: 'ignore',
});

subprocess.unref(); 

或者,可以将子进程的输出重定向到文件中:

const fs = require('node:fs');
const { spawn } = require('node:child_process');
const out = fs.openSync('./out.log', 'a');
const err = fs.openSync('./out.log', 'a');

const subprocess = spawn('prg', [], {
  detached: true,
  stdio: [ 'ignore', out, err ],
});

subprocess.unref(); 
options.stdio#

options.stdio选项用于配置在父进程和子进程之间建立的管道。默认情况下,子级的 stdin、stdout 和 stderr 会重定向到 ChildProcess对象上相应的subprocess.stdinsubprocess.stdoutsubprocess.stderr流 。这相当于将options.stdio设置 为等于['pipe', 'pipe', 'pipe']

为了方便起见,options.stdio可以是以下字符串之一:

  • 'pipe':相当于['pipe', 'pipe', 'pipe'](默认值)
  • 'overlapped':相当于['overlapped', 'overlapped', 'overlapped']
  • 'ignore':相当于['ignore', 'ignore', 'ignore']
  • 'inherit':相当于['inherit', 'inherit', 'inherit'][0, 1, 2]

否则, options.stdio的值是一个数组,其中每个索引对应于子级中的一个 fd。fds 0、1 和 2 分别对应于 stdin、stdout 和 stderr。可以指定附加的 fd 以在父级和子级之间创建附加管道。该值为以下之一:

  1. 'pipe':在子进程和父进程之间创建管道。管道的父端作为 child_process对象上的属性以subprocess.stdio[fd]的形式向父级公开。为 fd 0、1 和 2 创建的管道也可分别用作subprocess.stdinsubprocess.stdoutsubprocess.stderr。这些不是实际的 Unix 管道,因此子进程无法通过其描述符文件使用它们,例如/dev/fd/2/dev/stdout

  2. 'overlapped' :与'pipe'相同,只是在句柄上设置了FILE_FLAG_OVERLAPPED标志。这对于子进程的 stdio 句柄上的重叠 I/O 是必需的。请参阅 文档 了解更多详细信息。这与非 Windows 系统上的'pipe'完全相同。

  3. 'ipc':创建 IPC 通道,用于在父级和子级之间传递消息/文件描述符。一个ChildProcess最多可以有一个 IPC stdio 文件描述符。设置此选项将启用 subprocess.send()方法。如果子进程是 Node.js 进程,则 IPC 通道的存在将启用process.send()process.disconnect()方法,以及'disconnect''message'子进程内部的事件。

    不支持以process.send()以外的任何方式访问 IPC 通道 fd或将 IPC 通道与非 Node.js 实例的子进程一起使用。

  4. 'ignore':指示 Node.js 忽略子级中的 fd。虽然 Node.js 将始终为其生成的进程打开 fd 0、1 和 2,但将 fd 设置为'ignore'将导致 Node.js 打开/dev/null并将其附加到子进程FD。

  5. 'inherit':通过相应的 stdio 流传入/传出父进程。在前三个位置,这分别相当于 process.stdinprocess.stdoutprocess.stderr。在任何其他位置,相当于'ignore'

  6. <Stream>对象:与子进程共享引用 tty、文件、套接字或管道的可读或可写流。流的底层文件描述符在子进程中复制到与stdio数组中的索引相对应的 fd。流必须具有底层描述符(文件流只有在'open'事件发生后才具有)。

  7. 正整数:整数值被解释为在父进程中打开的文件描述符。它与子进程共享,类似于<Stream>对象的共享方式。Windows 不支持传递套接字。

  8. nullundefined:使用默认值。对于 stdio fds 0、1 和 2(即 stdin、stdout 和 stderr),将创建一个管道。对于 fd 3 及以上,默认值为'ignore'

const { spawn } = require('node:child_process');

// Child will use parent's stdios.
spawn('prg', [], { stdio: 'inherit' });

// Spawn child sharing only stderr.
spawn('prg', [], { stdio: ['pipe', 'pipe', process.stderr] });

// Open an extra fd=4, to interact with programs presenting a
// startd-style interface.
spawn('prg', [], { stdio: ['pipe', null, null, null, 'pipe'] }); 

值得注意的是,当父进程和子进程之间建立了 IPC 通道,并且子进程是 Node.js 进程时,子进程将在未引用 IPC 通道的情况下启动(使用 unref() ),直到子进程启动。为'disconnect'事件或'message'事件注册事件处理程序。这允许子进程正常退出,而进程不会被打开的 IPC 通道保持打开状态。

在类 Unix 操作系统上,child_process.spawn()方法在将事件循环与子级解耦之前同步执行内存操作。内存占用较大的应用程序可能会发现频繁的 child_process.spawn()调用成为瓶颈。有关更多信息,请参阅V8 问题 7381

另请参阅:child_process.exec()child_process.fork()

同步进程创建#

child_process.spawnSync()child_process.execSync()child_process.execFileSync()方法是同步的,将阻止 Node.js 事件循环,暂停任何其他代码的执行,直到生成的进程退出。

像这样的阻止调用对于简化通用脚本任务以及简化启动时应用程序配置的加载/处理非常有用。

child_process.execFileSync(file[, args][, options])#

  • file <string>要运行的可执行文件的名称或路径。
  • args <string[]>字符串参数列表。
  • options <对象>
    • cwd <字符串> | <URL>子进程的当前工作目录。
    • input <字符串> | <缓冲区> | <类型化数组> | <Da​​taView>将作为标准输入传递给生成进程的值。提供此值将覆盖 stdio[0]
    • stdio <字符串> | <Array>子进程的 stdio 配置。除非指定了stdio ,否则默认情况下stderr将输出到父进程的 stderr 。 默认值: 'pipe'
    • env <Object>环境键值对。默认值: process.env
    • uid <number>设置进程的用户身份(请参阅setuid(2))。
    • gid <number>设置进程的组标识(请参阅setgid(2))。
    • timeout <number>允许进程运行的最长时间(以毫秒为单位)。默认值: undefined
    • killSignal <字符串> | <integer>当生成的进程将被终止时使用的信号值。默认值: 'SIGTERM'
    • maxBuffer <number> stdout 或 stderr 上允许的最大数据量(以字节为单位)。如果超过,子进程将被终止。请参阅maxBuffer和 Unicode处的警告 。默认值: 1024 * 1024
    • encoding <string>用于所有 stdio 输入和输出的编码。 默认值: 'buffer'
    • windowsHide <boolean>隐藏通常在 Windows 系统上创建的子进程控制台窗口。默认值: false
    • shell <布尔值> | <string>如果true,则在 shell 内运行command 。在 Unix 上使用 '/bin/sh',在 Windows 上使用process.env.ComSpec 。可以将不同的 shell 指定为字符串。请参阅Shell 要求默认 Windows shell默认值: false(无Shell)。
  • 返回:<缓冲区> | <string>命令的标准输出。

child_process.execFileSync()方法通常与child_process.execFile()相同 ,但该方法在子进程完全关闭之前不会返回。当遇到超时并发送killSignal时,该方法将不会返回,直到进程完全退出。

如果子进程拦截并处理了SIGTERM信号并且没有退出,父进程仍然会等待,直到子进程退出。

如果进程超时或具有非零退出代码,此方法将抛出一个 Error ,其中将包含底层child_process.spawnSync()的完整结果 。

如果启用了shell选项,请勿将未经处理的用户输入传递给此函数。任何包含 shell 元字符的输入都可用于触发任意命令执行。

child_process.execSync(command[, options])#

  • command <string>要运行的命令。
  • options <对象>
    • cwd <字符串> | <URL>子进程的当前工作目录。
    • input <字符串> | <缓冲区> | <类型化数组> | <Da​​taView>将作为标准输入传递给生成进程的值。提供此值将覆盖 stdio[0]
    • stdio <字符串> | <Array>子进程的 stdio 配置。除非指定了stdio ,否则默认情况下stderr将输出到父进程的 stderr 。 默认值: 'pipe'
    • env <Object>环境键值对。默认值: process.env
    • shell <string>用于执行命令的 Shell。请参阅 Shell 要求默认 Windows shell默认值:在 Unix 上为 '/bin/sh',在 Windows 上为process.env.ComSpec
    • uid <number>设置进程的用户身份。(参见setuid(2))。
    • gid <number>设置进程的组标识。(参见setgid(2))。
    • timeout <number>允许进程运行的最长时间(以毫秒为单位)。默认值: undefined
    • killSignal <字符串> | <integer>当生成的进程将被终止时使用的信号值。默认值: 'SIGTERM'
    • maxBuffer <number> stdout 或 stderr 上允许的最大数据量(以字节为单位)。如果超过,子进程将被终止,所有输出都会被截断。请参阅maxBuffer和 Unicode处的警告。 默认值: 1024 * 1024
    • encoding <string>用于所有 stdio 输入和输出的编码。 默认值: 'buffer'
    • windowsHide <boolean>隐藏通常在 Windows 系统上创建的子进程控制台窗口。默认值: false
  • 返回:<缓冲区> | <string>命令的标准输出。

child_process.execSync()方法通常与child_process.exec()相同 ,但该方法在子进程完全关闭之前不会返回。当遇到超时并发送killSignal时,该方法将不会返回,直到进程完全退出。如果子进程拦截并处理了SIGTERM 信号并且没有退出,则父进程将等待,直到子进程退出。

如果进程超时或具有非零退出代码,则此方法将抛出异常。Error对象将包含child_process.spawnSync()的整个结果 。

切勿将未经处理的用户输入传递给此函数。任何包含 shell 元字符的输入都可用于触发任意命令执行。

child_process.spawnSync(command[, args][, options])#

  • command <string>要运行的命令。
  • args <string[]>字符串参数列表。
  • options <对象>
    • cwd <字符串> | <URL>子进程的当前工作目录。
    • input <字符串> | <缓冲区> | <类型化数组> | <Da​​taView>将作为标准输入传递给生成进程的值。提供此值将覆盖 stdio[0]
    • argv0 <string>显式设置发送到子进程的argv[0]的值。如果未指定,这将设置为command
    • stdio <字符串> | <Array>子进程的 stdio 配置。
    • env <对象>环境键值对。默认值: process.env
    • uid <number>设置进程的用户身份(请参阅setuid(2))。
    • gid <number>设置进程的组标识(请参阅setgid(2))。
    • timeout <number>允许进程运行的最长时间(以毫秒为单位)。默认值: undefined
    • killSignal <字符串> | <integer>当生成的进程将被终止时使用的信号值。默认值: 'SIGTERM'
    • maxBuffer <number> stdout 或 stderr 上允许的最大数据量(以字节为单位)。如果超过,子进程将被终止,所有输出都会被截断。请参阅maxBuffer和 Unicode处的警告。 默认值: 1024 * 1024
    • encoding <string>用于所有 stdio 输入和输出的编码。 默认值: 'buffer'
    • shell <布尔值> | <string>如果true,则在 shell 内运行command 。在 Unix 上使用 '/bin/sh',在 Windows 上使用 process.env.ComSpec 。可以将不同的 shell 指定为字符串。请参阅Shell 要求默认 Windows shell默认值: false(无Shell)。
    • windowsVerbatimArguments <boolean> Windows 上不会对参数进行引用或转义。在 Unix 上被忽略。当指定 shell且为 CMD时,此值会自动设置为 true默认值:false
    • windowsHide <boolean>隐藏通常在 Windows 系统上创建的子进程控制台窗口。默认值: false
  • 返回:<对象>

child_process.spawnSync()方法通常与child_process.spawn()相同 ,但该函数在子进程完全关闭之前不会返回。当遇到超时并发送killSignal时,该方法将不会返回,直到进程完全退出。如果进程拦截并处理了SIGTERM信号并且没有退出,则父进程将等待,直到子进程退出。

如果启用了shell选项,请勿将未经处理的用户输入传递给此函数。任何包含 shell 元字符的输入都可用于触发任意命令执行。

类:ChildProcess#

ChildProcess的实例代表生成的子进程。

ChildProcess的实例不适合直接创建。相反,请使用child_process.spawn()child_process.exec()child_process.execFile()child_process.fork()方法创建ChildProcess的实例。

事件:'close'#

  • code <number>子进程自行退出时的退出代码。
  • signal <string>终止子进程的信号。

进程结束子进程的 stdio 流关闭后,会发出'close'事件。这与 'exit'事件不同,因为多个进程可能共享相同的 stdio 流。'close'事件将始终在'exit'已发出后发出,如果子级未能生成,则为'error'

const { spawn } = require('node:child_process');
const ls = spawn('ls', ['-lh', '/usr']);

ls.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

ls.on('close', (code) => {
  console.log(`child process close all stdio with code ${code}`);
});

ls.on('exit', (code) => {
  console.log(`child process exited with code ${code}`);
}); 

事件:'disconnect'#

在父进程中调用 subprocess.disconnect()方法或 在子进程中调用process.disconnect() 方法后,会发出 'disconnect' 事件 。断开连接后,无法再发送或接收消息,并且subprocess.connected 属性为false

事件:'error'#

  • err <错误>错误。

只要出现以下情况,就会发出'error'事件:

  • 无法生成该进程。
  • 该进程无法被终止。
  • 向子进程发送消息失败。
  • 子进程已通过signal选项中止。

发生错误后,'exit'事件可能会触发,也可能不会触发。在侦听'exit''error'事件时,请防止意外多次调用处理函数。

另请参阅subprocess.kill()subprocess.send()

事件:'exit'#

  • code <number>子进程自行退出时的退出代码。
  • signal <string>终止子进程的信号。

'exit'事件在子进程结束后发出。如果进程退出,则code是进程的最终退出代码,否则null。如果进程由于收到信号而终止,则signal是信号的字符串名称,否则为null。两者之一始终是非null

当触发'exit'事件时,子进程 stdio 流可能仍处于打开状态。

Node.js 为SIGINTSIGTERM建立信号处理程序,Node.js 进程不会因收到这些信号而立即终止。相反,Node.js 将执行一系列清理操作,然后重新引发已处理的信号。

请参阅waitpid(2)

事件:'message'#

当子进程使用 process.send()发送消息时,会触发 'message'事件。

消息经过序列化和解析。结果消息可能与最初发送的消息不同。

如果在生成子进程时将serialization选项设置为'advanced' ,则message参数可能包含 JSON 无法表示的数据。有关更多详细信息,请参阅高级序列化

事件:'spawn'#

一旦子进程成功生成,就会发出'spawn'事件。如果子进程未成功生成,则不会发出'spawn'事件,而是发出'error'事件。

如果发出,则'spawn'事件先于所有其他事件以及通过stdoutstderr接收任何数据之前发生。

无论 生成的进程中是否发生错误,都会触发'spawn'事件。例如,如果bash some-command成功生成,则'spawn'事件将触发,但bash可能无法生成some-command。使用{ shell: true }时,此警告也适用。

subprocess.channel#

  • <Object>表示子进程的 IPC 通道的管道。

subprocess.channel属性是对子级 IPC 通道的引用。如果不存在 IPC 通道,则此属性为undefined

subprocess.channel.ref()#

如果之前调用过.unref(),则此方法使 IPC 通道保持父进程的事件循环运行。

subprocess.channel.unref()#

此方法使 IPC 通道不保持父进程的事件循环运行,并让它在通道打开时完成。

subprocess.connected#

  • <boolean>在调用subprocess.disconnect()后设置为false

subprocess.connected属性指示是否仍然可以从子进程发送和接收消息。当subprocess.connectedfalse时,无法再发送或接收消息。

subprocess.disconnect()#

关闭父进程和子进程之间的 IPC 通道,允许子进程在没有其他连接保持事件状态时正常退出。调用此方法后,父级和子级中的subprocess.connectedprocess.connected属性(分别)将设置为false,并且将不再可能在进程之间传递消息。

当接收过程中没有消息时,将发出'disconnect'事件。这通常会在调用subprocess.disconnect()后立即触发。

当子进程是 Node.js 实例时(例如使用 child_process.fork()生成),也可以在子进程中调用process.disconnect()方法来关闭 IPC 通道。

subprocess.exitCode#

subprocess.exitCode属性指示子进程的退出代码。如果子进程仍在运行,则该字段将为null

subprocess.kill([signal])#

subprocess.kill()方法向子进程发送信号。如果没有给出参数,进程将被发送'SIGTERM'信号。请参阅 signal(7)以获取可用信号的列表。如果 kill(2) 成功,此函数返回 true ,否则返回false

const { spawn } = require('node:child_process');
const grep = spawn('grep', ['ssh']);

grep.on('close', (code, signal) => {
  console.log(
    `child process terminated due to receipt of signal ${signal}`);
});

// Send SIGHUP to process.
grep.kill('SIGHUP'); 

如果信号无法传递,则ChildProcess对象可能会发出'error'事件。向已退出的子进程发送信号并不是错误,但可能会产生不可预见的后果。具体来说,如果进程标识符 (PID) 已重新分配给另一个进程,则信号将传递给该进程,而这可能会产生意外结果。

虽然调用该函数kill,但传递给子进程的信号可能不会真正终止该进程。

请参阅kill(2)以供参考。

在 Windows 上,由于不存在 POSIX 信号,因此signal参数将被忽略,进程将被突然强制终止(类似于 'SIGKILL')。有关更多详细信息,请参阅信号事件

在 Linux 上,当尝试杀死其父进程时,子进程的子进程不会被终止。在 shell 中运行新进程或使用ChildProcessshell选项时,可能会发生这种情况:

'use strict';
const { spawn } = require('node:child_process');

const subprocess = spawn(
  'sh',
  [
    '-c',
    `node -e "setInterval(() => {
      console.log(process.pid, 'is alive')
    }, 500);"`,
  ], {
    stdio: ['inherit', 'inherit', 'inherit'],
  },
);

setTimeout(() => {
  subprocess.kill(); // Does not terminate the Node.js process in the shell.
}, 2000); 

subprocess[Symbol.dispose]()#

稳定性:1 - 实验性

使用'SIGTERM'调用subprocess.kill()

subprocess.killed#

  • <boolean>在使用subprocess.kill()后设置为true用于成功向子进程发送信号。

subprocess.killed属性指示子进程是否成功接收到来自subprocess.kill()的信号。killed属性并不表示子进程已终止。

subprocess.pid#

返回子进程的进程标识符 (PID)。如果子进程由于错误而未能生成,则值为undefined并发出error

const { spawn } = require('node:child_process');
const grep = spawn('grep', ['ssh']);

console.log(`Spawned child pid: ${grep.pid}`);
grep.stdin.end(); 

subprocess.ref()#

在调用subprocess.unref()之后调用subprocess.unref()将恢复子进程已删除的引用计数,强制父进程等待子进程退出后再退出。

const { spawn } = require('node:child_process');

const subprocess = spawn(process.argv[0], ['child_program.js'], {
  detached: true,
  stdio: 'ignore',
});

subprocess.unref();
subprocess.ref(); 

subprocess.send(message[, sendHandle[, options]][, callback])#

  • message <对象>
  • sendHandle <句柄>
  • options <Object> options参数(如果存在)是用于参数化某些类型句柄的发送的对象。options支持以下属性:
    • keepOpen <boolean>传递net.Socket实例时可以使用的值 。当true时,套接字在发送过程中保持打开状态。 默认值: false
  • callback <函数>
  • 返回:<布尔值>

当父进程和子进程之间建立了 IPC 通道时(即使用child_process.fork()时),可以使用subprocess.send()方法向子进程发送消息。当子进程是 Node.js 实例时,可以通过'message'事件接收这些消息。

消息经过序列化和解析。结果消息可能与最初发送的消息不同。

例如,在父脚本中:

const cp = require('node:child_process');
const n = cp.fork(`${__dirname}/sub.js`);

n.on('message', (m) => {
  console.log('PARENT got message:', m);
});

// Causes the child to print: CHILD got message: { hello: 'world' }
n.send({ hello: 'world' }); 

然后子脚本'sub.js'可能如下所示:

process.on('message', (m) => {
  console.log('CHILD got message:', m);
});

// Causes the parent to print: PARENT got message: { foo: 'bar', baz: null }
process.send({ foo: 'bar', baz: NaN }); 

Node.js 子进程将拥有自己的process.send()方法,允许子进程将消息发送回父进程。

发送{cmd: 'NODE_foo'}消息时有一种特殊情况。cmd属性中包含NODE_前缀的消息保留在 Node.js 核心内使用,并且不会在子级的'message' 事件中发出。相反,此类消息是使用 'internalMessage'事件发出的,并由 Node.js 在内部使用。应用程序应避免使用此类消息或监听 'internalMessage'事件,因为它可能会发生更改,恕不另行通知。

可以传递给subprocess.send()的可选sendHandle参数用于将 TCP 服务器或套接字对象传递给子进程。子级将接收该对象作为传递给在'message'事件上注册的回调函数的第二个参数。套接字中接收和缓冲的任何数据都不会发送给子进程。

可选的callback是在消息发送后但子级收到消息之前调用的函数。该函数使用单个参数调用:成功时使用null,失败时使用 Error对象。

如果没有提供 callback函数并且无法发送消息,则ChildProcess对象将发出'error'事件。例如,当子进程已经退出时,可能会发生这种情况。

如果通道已关闭或未发送消息的积压超过阈值而导致发送更多消息不明智,则 subprocess.send()将返回false。否则,该方法返回truecallback函数可用于实现流量控制。

示例:发送服务器对象#

例如,可以使用sendHandle参数将 TCP 服务器对象的句柄传递给子进程,如下例所示:

const subprocess = require('node:child_process').fork('subprocess.js');

// Open up the server object and send the handle.
const server = require('node:net').createServer();
server.on('connection', (socket) => {
  socket.end('handled by parent');
});
server.listen(1337, () => {
  subprocess.send('server', server);
}); 

然后,子进程将收到服务器对象:

process.on('message', (m, server) => {
  if (m === 'server') {
    server.on('connection', (socket) => {
      socket.end('handled by child');
    });
  }
}); 

一旦服务器现在在父级和子级之间共享,一些连接可以由父级处理,一些连接可以由子级处理。

虽然上面的示例使用使用node:net模块创建的服务器,但 node:dgram模块服务器使用完全相同的工作流程,但监听'message'事件而不是'connection'并使用 server.bind()而不是server.listen()。然而,这仅在 Unix 平台上受支持。

示例:发送套接字对象#

同样,sendHandler参数可用于将套接字的句柄传递给子进程。下面的示例生成两个子级,每个子级都处理具有“正常”或“特殊”优先级的连接:

const { fork } = require('node:child_process');
const normal = fork('subprocess.js', ['normal']);
const special = fork('subprocess.js', ['special']);

// Open up the server and send sockets to child. Use pauseOnConnect to prevent
// the sockets from being read before they are sent to the child process.
const server = require('node:net').createServer({ pauseOnConnect: true });
server.on('connection', (socket) => {

  // If this is special priority...
  if (socket.remoteAddress === '74.125.127.100') {
    special.send('socket', socket);
    return;
  }
  // This is normal priority.
  normal.send('socket', socket);
});
server.listen(1337); 

subprocess.js将接收套接字句柄作为传递给事件回调函数的第二个参数:

process.on('message', (m, socket) => {
  if (m === 'socket') {
    if (socket) {
      // Check that the client socket exists.
      // It is possible for the socket to be closed between the time it is
      // sent and the time it is received in the child process.
      socket.end(`Request handled with ${process.argv[2]} priority`);
    }
  }
}); 

不要在已传递给子进程的套接字上使用.maxConnections 。父级无法跟踪套接字何时被销毁。

子进程中的任何'message'处理程序都应验证socket是否存在,因为在将连接发送到子进程期间连接可能已关闭。

subprocess.signalCode#

subprocess.signalCode属性指示子进程接收到的信号(如果有),否则为null

subprocess.spawnargs#

subprocess.spawnargs属性表示启动子进程时使用的命令行参数的完整列表。

subprocess.spawnfile#

subprocess.spawnfile属性指示启动的子进程的可执行文件名。

对于child_process.fork(),其值将等于 process.execPath。对于child_process.spawn(),其值将是可执行文件的名称。对于child_process.exec(),其值将是启动子进程的 shell 的名称。

subprocess.stderr#

代表子进程的stderrReadable Stream

如果子级是在stdio[2]设置为'pipe'以外的任何值的情况下生成的,那么这将是null

subprocess.stderrsubprocess.stdio[2]的别名。这两个属性将引用相同的值。

如果无法成功生成子进程,则subprocess.stderr属性可以是nullundefined

subprocess.stdin#

代表子进程的stdinWritable Stream

如果子进程等待读取其所有输入,则子进程将不会继续,直到通过end()关闭该流。

如果子级是在stdio[0]设置为'pipe'以外的任何值的情况下生成的,那么这将是null

subprocess.stdinsubprocess.stdio[0]的别名。这两个属性将引用相同的值。

如果无法成功生成子进程,则subprocess.stdin属性可以是nullundefined

subprocess.stdio#

子进程的稀疏管道数组,与传递给child_process.spawn()stdio 选项中已设置为值'pipe'的位置相对应。subprocess.stdio[0]subprocess.stdio[1]subprocess.stdio[2]也可用作subprocess.stdinsubprocess.stdoutsubprocess.stderr, 分别。

在以下示例中,只有子级的 fd 1 (stdout) 配置为管道,因此只有父级的subprocess.stdio[1]是流,数组中的所有其他值都是null

const assert = require('node:assert');
const fs = require('node:fs');
const child_process = require('node:child_process');

const subprocess = child_process.spawn('ls', {
  stdio: [
    0, // Use parent's stdin for child.
    'pipe', // Pipe child's stdout to parent.
    fs.openSync('err.out', 'w'), // Direct child's stderr to a file.
  ],
});

assert.strictEqual(subprocess.stdio[0], null);
assert.strictEqual(subprocess.stdio[0], subprocess.stdin);

assert(subprocess.stdout);
assert.strictEqual(subprocess.stdio[1], subprocess.stdout);

assert.strictEqual(subprocess.stdio[2], null);
assert.strictEqual(subprocess.stdio[2], subprocess.stderr); 

如果无法成功生成子进程,则subprocess.stdio属性可以为undefined

subprocess.stdout#

代表子进程的stdoutReadable Stream

如果子级是在stdio[1]设置为'pipe'以外的任何值的情况下生成的,那么这将是null

subprocess.stdoutsubprocess.stdio[1]的别名。这两个属性将引用相同的值。

const { spawn } = require('node:child_process');

const subprocess = spawn('ls');

subprocess.stdout.on('data', (data) => {
  console.log(`Received chunk ${data}`);
}); 

如果无法成功生成子进程,则subprocess.stdout属性可以是nullundefined

subprocess.unref()#

默认情况下,父进程将等待分离的子进程退出。要防止父级等待给定的subprocess退出,请使用 subprocess.unref()方法。这样做将导致父级的事件循环不将子级包含在其引用计数中,从而允许父级独立于子级退出,除非子级和父级之间已建立 IPC 通道。

const { spawn } = require('node:child_process');

const subprocess = spawn(process.argv[0], ['child_program.js'], {
  detached: true,
  stdio: 'ignore',
});

subprocess.unref(); 

maxBuffer和 Unicode#

maxBuffer选项指定stdoutstderr上允许的最大字节数。如果超过该值,则子进程将终止。这会影响包括 UTF-8 或 UTF-16 等多字节字符编码的输出。例如,console.log('中文测试')将向stdout发送 13 个 UTF-8 编码字节,尽管只有 4 个字符。

Shell要求#

shell 应该理解-c开关。如果 shell 是'cmd.exe',它应该理解/d /s /c开关,并且命令行解析应该兼容。

默认 Windows shell#

尽管 Microsoft 规定%COMSPEC%必须包含根环境中'cmd.exe'的路径 ,但子进程并不总是遵循相同的要求。因此,在可以生成 shell 的child_process函数中,如果process.env.ComSpec不可用,则使用'cmd.exe'作为后备。

高级序列化#

子进程支持IPC的序列化机制,该机制基于 node:v8模块的序列化API,基于 HTML结构化克隆算法。这通常更强大并且支持更多内置 JavaScript 对象类型,例如BigIntMapSetArrayBufferTypedArrayBufferErrorRegExp等。

然而,这种格式并不是 JSON 的完整超集,例如,在此类内置类型的对象上设置的属性将不会通过序列化步骤传递。此外,性能可能与 JSON 不同,具体取决于传递数据的结构。因此,此功能需要在调用child_process.spawn()child_process.fork() 时将 serialization选项设置为'advanced'来选择加入 。

NodeJS中文文档为Read dev Docs平台提供托管,中文NodeJS文档均由英文版NodeJS文档翻译,版权属于nodejs.org