Node.js v20.2.0 文档


目录

子进程#

稳定性: 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 的管道。 这些管道的容量有限(且特定于平台)。 如果子进程在没有捕获输出的情况下写入标准输出超过该限制,则子进程会阻塞等待管道缓冲区接受更多数据。 这与 shell 中管道的行为相同。 如果不消费输出,则使用 { stdio: 'ignore' } 选项。

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

在 Windows 上,环境变量不区分大小写。 Node.js 按字典顺序对 env 键进行排序,并使用不区分大小写匹配的第一个键。 只有第一个(按字典顺序)条目将传给子流程。 当传给 env 选项的对象具有多个相同键名的变体时(例如 PATHPath),在 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 上运行时,.bat.cmd 文件可以使用具有 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 参数将包含子进程的标准输出和标准错误的输出。 默认情况下,Node.js 会将输出解码为 UTF-8 并将字符串传给回调。 encoding 选项可用于指定用于解码标准输出和标准错误的输出的字符编码。 如果 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,则如果子进程运行时间超过 timeout 毫秒,父进程将发送由 killSignal 属性(默认为 'SIGTERM')标识的信号。

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

如果此方法作为其 util.promisify() 版本被调用,则其将为具有 stdoutstderr 属性的 Object 返回 Promise。 返回的 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])#

  • file <string> 要运行的可执行文件的名称或路径。
  • args <string[]> 字符串参数列表。
  • options <Object>
    • cwd <string> | <URL> 子进程的当前工作目录。
    • env <Object> 环境变量键值对。 默认值: process.env
    • encoding <string> 默认值: 'utf8'
    • timeout <number> 默认值: 0
    • maxBuffer <number> 标准输出或标准错误上允许的最大数据量(以字节为单位)。 如果超过,则子进程将终止并截断任何输出。 请参阅 maxBuffer 和 Unicode 的警告。 默认值: 1024 * 1024
    • killSignal <string> | <integer> 默认值: 'SIGTERM'
    • uid <number> 设置进程的用户标识(参见 setuid(2))。
    • gid <number> 设置进程的群组标识(参见 setgid(2))。
    • windowsHide <boolean> 隐藏通常在 Windows 系统上创建的子进程控制台窗口。 默认值: false
    • windowsVerbatimArguments <boolean> 在 Windows 上不为参数加上引号或转义。 在 Unix 上被忽略。 默认值: false
    • shell <boolean> | <string> 如果是 true,则在 shell 内运行 command。 在 Unix 上使用 '/bin/sh',在 Windows 上使用 process.env.ComSpec。 可以将不同的 shell 指定为字符串。 参见 Shell 要求默认 Windows shell默认值: false(无 shell)。
    • signal <AbortSignal> 允许使用中止信号中止子进程。
  • callback <Function> 进程终止时使用输出调用。
  • 返回: <ChildProcess>

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

如果此方法作为其 util.promisify() 版本被调用,则其将为具有 stdoutstderr 属性的 Object 返回 Promise。 返回的 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 <string> | <URL> 要在子进程中运行的模块。
  • args <string[]> 字符串参数列表。
  • options <Object>
    • cwd <string> | <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> 允许使用中止信号关闭子进程。
    • killSignal <string> | <integer> 当衍生的进程将被超时或中止信号杀死时要使用的信号值。 默认值: 'SIGTERM'
    • silent <boolean> 如果为 true,则子进程的标准输入、标准输出和标准错误将通过管道传输到父进程,否则它们将从父进程继承,有关详细信息,请参阅 child_process.spawn()stdio'pipe''inherit' 选项。 默认值: false
    • stdio <Array> | <string> 参见 child_process.spawn()stdio。 提供此选项时,它会覆盖 silent。 如果使用数组变体,则它必须恰好包含一个值为 'ipc' 的条目,否则将抛出错误。 例如 [0, 1, 2, 'ipc']
    • uid <number> 设置进程的用户标识(参见 setuid(2))。
    • windowsVerbatimArguments <boolean> 在 Windows 上不为参数加上引号或转义。 在 Unix 上被忽略。 默认值: false
    • timeout <number> 允许进程运行的最长时间(以毫秒为单位)。 默认值: undefined
  • 返回: <ChildProcess>

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 标识的文件描述符与父进程通信。

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

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

如果启用了 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 <Object>
    • cwd <string> | <URL> 子进程的当前工作目录。
    • env <Object> 环境变量键值对。 默认值: process.env
    • argv0 <string> 显式设置发送给子进程的 argv[0] 的值。 如果未指定,这将设置为 command
    • stdio <Array> | <string> 子进程的标准输入输出配置(参见 options.stdio)。
    • detached <boolean> 准备子进程独立于其父进程运行。 具体行为取决于平台,参见 options.detached
    • uid <number> 设置进程的用户标识(参见 setuid(2))。
    • gid <number> 设置进程的群组标识(参见 setgid(2))。
    • serialization <string> 指定用于在进程之间发送消息的序列化类型。 可能的值为 'json''advanced'。 有关详细信息,请参阅 高级序列化默认值: 'json'
    • shell <boolean> | <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> 允许使用中止信号中止子进程。
    • timeout <number> 允许进程运行的最长时间(以毫秒为单位)。 默认值: undefined
    • killSignal <string> | <integer> 当衍生的进程将被超时或中止信号杀死时要使用的信号值。 默认值: 'SIGTERM'
  • 返回: <ChildProcess>

child_process.spawn() 方法使用给定的 commandargs 中的命令行参数衍生新进程。 如果省略,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] 不会匹配从父进程传给 spawnargv0 参数。 改为使用 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 选项用于配置在父进程和子进程之间建立的管道。 默认情况下,子进程的标准输入、标准输出和标准错误被重定向到 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 的值是一个数组,其中每个索引对应于子进程中的文件描述符。 文件描述符 0、1 和 2 分别对应于标准输入、标准输出和标准错误。 可以指定额外的文件描述符以在父进程和子进程之间创建额外的管道。 该值是以下之一:

  1. 'pipe': 在子进程和父进程之间创建管道。 管道的父端作为 subprocess.stdio[fd] 对象上的 child_process 对象的属性公开给父级。 为 fds 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 将始终为其生成的进程打开 fds 0、1 和 2,但将 fd 设置为 'ignore' 将导致 Node.js 打开 /dev/null 并将其附加到子进程的 fd。

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

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

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

  8. null, undefined: 使用默认值。 对于 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 <Object>
    • cwd <string> | <URL> 子进程的当前工作目录。
    • input <string> | <Buffer> | <TypedArray> | <DataView> 将作为标准输入传给衍生进程的值。 提供此值将覆盖 stdio[0]
    • stdio <string> | <Array> 子进程的标准输入输出配置。 除非指定 stdio,否则默认情况下 stderr 将输出到父进程的标准错误。 默认值: 'pipe'
    • env <Object> 环境变量键值对。 默认值: process.env
    • uid <number> 设置进程的用户标识(参见 setuid(2))。
    • gid <number> 设置进程的群组标识(参见 setgid(2))。
    • timeout <number> 允许进程运行的最长时间(以毫秒为单位)。 默认值: undefined
    • killSignal <string> | <integer> 衍生的进程将被终止时要使用的信号值。 默认值: 'SIGTERM'
    • maxBuffer <number> 标准输出或标准错误上允许的最大数据量(以字节为单位)。 如果超过,则终止子进程。 请参阅 maxBuffer 和 Unicode 的警告。 默认值: 1024 * 1024
    • encoding <string> 用于所有标准输入输出的输入和输出的编码。 默认值: 'buffer'
    • windowsHide <boolean> 隐藏通常在 Windows 系统上创建的子进程控制台窗口。 默认值: false
    • shell <boolean> | <string> 如果是 true,则在 shell 内运行 command。 在 Unix 上使用 '/bin/sh',在 Windows 上使用 process.env.ComSpec。 可以将不同的 shell 指定为字符串。 参见 Shell 要求默认 Windows shell默认值: false(无 shell)。
  • 返回: <Buffer> | <string> 命令的标准输出。

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

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

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

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

child_process.execSync(command[, options])#

  • command <string> 要运行的命令。
  • options <Object>
    • cwd <string> | <URL> 子进程的当前工作目录。
    • input <string> | <Buffer> | <TypedArray> | <DataView> 将作为标准输入传给衍生进程的值。 提供此值将覆盖 stdio[0]
    • stdio <string> | <Array> 子进程的标准输入输出配置。 除非指定 stdio,否则默认情况下 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 <string> | <integer> 衍生的进程将被终止时要使用的信号值。 默认值: 'SIGTERM'
    • maxBuffer <number> 标准输出或标准错误上允许的最大数据量(以字节为单位)。 如果超过,则子进程将终止并截断任何输出。 请参阅 maxBuffer 和 Unicode 的警告。 默认值: 1024 * 1024
    • encoding <string> 用于所有标准输入输出的输入和输出的编码。 默认值: 'buffer'
    • windowsHide <boolean> 隐藏通常在 Windows 系统上创建的子进程控制台窗口。 默认值: false
  • 返回: <Buffer> | <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 <Object>
    • cwd <string> | <URL> 子进程的当前工作目录。
    • input <string> | <Buffer> | <TypedArray> | <DataView> 将作为标准输入传给衍生进程的值。 提供此值将覆盖 stdio[0]
    • argv0 <string> 显式设置发送给子进程的 argv[0] 的值。 如果未指定,这将设置为 command
    • stdio <string> | <Array> 子进程的标准输入输出配置。
    • env <Object> 环境变量键值对。 默认值: process.env
    • uid <number> 设置进程的用户标识(参见 setuid(2))。
    • gid <number> 设置进程的群组标识(参见 setgid(2))。
    • timeout <number> 允许进程运行的最长时间(以毫秒为单位)。 默认值: undefined
    • killSignal <string> | <integer> 衍生的进程将被终止时要使用的信号值。 默认值: 'SIGTERM'
    • maxBuffer <number> 标准输出或标准错误上允许的最大数据量(以字节为单位)。 如果超过,则子进程将终止并截断任何输出。 请参阅 maxBuffer 和 Unicode 的警告。 默认值: 1024 * 1024
    • encoding <string> 用于所有标准输入输出的输入和输出的编码。 默认值: 'buffer'
    • shell <boolean> | <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
  • 返回: <Object>
    • pid <number> 子进程的 pid。
    • output <Array> 来自标准输入输出的输出的结果数组。
    • stdout <Buffer> | <string> output[1] 的内容。
    • stderr <Buffer> | <string> output[2] 的内容。
    • status <number> | <null> 子进程的退出码,如果子进程因信号而终止,则为 null
    • signal <string> | <null> 用于终止子进程的信号,如果子进程没有因信号而终止,则为 null
    • error <Error> 如果子进程失败或超时,则为错误对象。

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> 终止子进程的信号。

'close' 事件在进程结束并且子进程的 stdio 流关闭后触发。 这与 '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'#

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

事件:'error'#

'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)

在不存在 POSIX 信号的 Windows 上,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.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.ref() 将恢复为子进程删除的引用计数,迫使父进程在退出自身之前等待子进程退出。

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

当父进程和子进程之间已经建立了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 参数可用于将套接字句柄传递给子进程。 下面的示例生成两个子节点,每个子节点处理具有 "normal" 或 "special" 优先级的连接:

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)的输出。 例如,虽然只有 4 个字符,但 console.log('中文测试') 将向 stdout 发送 13 个 UTF-8 编码字节。

Shell 要求#

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

默认 Windows shell#

虽然 Microsoft 指定 %COMSPEC% 必须包含根环境中的 'cmd.exe' 路径,但子进程并不总是符合相同的要求。 因此,在可以生成 shell 的 child_process 函数中,如果 process.env.ComSpec 不可用,则将 'cmd.exe' 用作回退。

高级序列化#

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

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