Node.js v21.7.2 文档
- Node.js v21.7.2
-
► 目录
- 子进程
- 异步进程创建
- 同步进程创建
- 类:
ChildProcess
- 事件:
'close'
- 事件:
'disconnect'
- 事件:
'error'
- 事件:
'exit'
- 事件:
'message'
- 事件:
'spawn'
subprocess.channel
subprocess.connected
subprocess.disconnect()
subprocess.exitCode
subprocess.kill([signal])
subprocess[Symbol.dispose]()
subprocess.killed
subprocess.pid
subprocess.ref()
subprocess.send(message[, sendHandle[, options]][, callback])
subprocess.signalCode
subprocess.spawnargs
subprocess.spawnfile
subprocess.stderr
subprocess.stdin
subprocess.stdio
subprocess.stdout
subprocess.unref()
- 事件:
maxBuffer
和 Unicode- Shell 要求
- 默认 Windows shell
- 高级序列化
- 子进程
-
► 索引
- 断言测试
- 异步上下文跟踪
- 异步钩子
- 缓冲区
- C++ 附加模块
- 使用 Node-API 的 C/C++ 附加模块
- C++ 嵌入器 API
- 子进程
- 集群
- 命令行选项
- 控制台
- Corepack
- 加密
- 调试器
- 已弃用的 API
- 诊断通道
- DNS
- 域
- 错误
- 事件
- 文件系统
- 全局对象
- HTTP
- HTTP/2
- HTTPS
- 检查器
- 国际化
- 模块:CommonJS 模块
- 模块:ECMAScript 模块
- 模块:
node:module
API - 模块:包
- 网络
- 操作系统
- 路径
- 性能钩子
- 权限
- 进程
- Punycode
- 查询字符串
- 读取行
- REPL
- 报告
- 单一可执行应用程序
- 流
- 字符串解码器
- 测试运行器
- 计时器
- TLS/SSL
- 跟踪事件
- TTY
- UDP/数据报
- URL
- 实用工具
- V8
- VM
- WASI
- Web Crypto API
- Web Streams API
- 工作线程
- Zlib
- ► 其他版本
- ► 选项
子进程#
源代码: 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}`);
});
默认情况下,stdin
、stdout
和 stderr
的管道在父 Node.js 进程和生成的子进程之间建立。这些管道具有有限的(并且特定于平台的)容量。如果子进程向 stdout 写入超过该限制的数据,而没有捕获输出,则子进程会阻塞,等待管道缓冲区接受更多数据。这与 shell 中管道的行为相同。如果输出不会被使用,请使用 { stdio: 'ignore' }
选项。
如果 options
对象中存在 env
,则命令查找将使用 options.env.PATH
环境变量执行。否则,将使用 process.env.PATH
。如果设置了 options.env
但没有 PATH
,则在 Unix 上,查找将在默认搜索路径 /usr/bin:/bin
上执行(有关详细信息,请参阅您的操作系统的 execvpe/execvp 手册),在 Windows 上,将使用当前进程的环境变量 PATH
。
在 Windows 上,环境变量不区分大小写。Node.js 会按字典顺序对 env
键进行排序,并使用第一个与之不区分大小写匹配的键。只有第一个(按字典顺序)条目将传递给子进程。这可能会导致在 Windows 上将具有相同键的多个变体的对象传递给 env
选项时出现问题,例如 PATH
和 Path
。
child_process.spawn()
方法异步生成子进程,不会阻塞 Node.js 事件循环。 child_process.spawnSync()
函数以同步方式提供等效的功能,该功能会阻塞事件循环,直到生成的进程退出或终止。
为了方便起见,node:child_process
模块提供了一些同步和异步的替代方法,用于替代 child_process.spawn()
和 child_process.spawnSync()
。这些替代方法都是基于 child_process.spawn()
或 child_process.spawnSync()
实现的。
child_process.exec()
: 生成一个 shell 并运行该 shell 中的命令,在命令完成时将stdout
和stderr
传递给回调函数。child_process.execFile()
: 与child_process.exec()
类似,但它默认直接生成命令,而不是先生成一个 shell。child_process.fork()
: 生成一个新的 Node.js 进程并调用指定的模块,并建立一个 IPC 通信通道,允许在父进程和子进程之间发送消息。child_process.execSync()
:child_process.exec()
的同步版本,它会阻塞 Node.js 事件循环。child_process.execFileSync()
:child_process.execFile()
的同步版本,它会阻塞 Node.js 事件循环。
对于某些用例,例如自动化 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 上运行时,可以使用 child_process.spawn()
(设置 shell
选项)、child_process.exec()
或生成 cmd.exe
并将 .bat
或 .cmd
文件作为参数传递来调用 .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])
#
command
<string> 要运行的命令,带空格分隔的参数。options
<Object>cwd
<string> | <URL> 子进程的当前工作目录。默认值:process.cwd()
。env
<Object> 环境键值对。默认值:process.env
。encoding
<string> 默认值:'utf8'
shell
<string> 用于执行命令的 Shell。参见 Shell 要求 和 默认 Windows Shell。默认值:Unix 上为'/bin/sh'
,Windows 上为process.env.ComSpec
。signal
<AbortSignal> 允许使用 AbortSignal 中止子进程。timeout
<number> 默认值:0
maxBuffer
<number> stdout 或 stderr 上允许的最大数据量(以字节为单位)。如果超过此限制,子进程将被终止,任何输出都将被截断。参见maxBuffer
和 Unicode 处的注意事项。默认值:1024 * 1024
。killSignal
<string> | <integer> 默认值:'SIGTERM'
uid
<number> 设置进程的用户标识(参见setuid(2)
)。gid
<number> 设置进程的组标识(参见setgid(2)
)。windowsHide
<boolean> 隐藏在 Windows 系统上通常会创建的子进程控制台窗口。默认值:false
。
callback
<Function> 在进程终止时使用输出调用。- 返回值: <ChildProcess>
生成一个 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
将是终止进程的信号。
传递给回调的 stdout
和 stderr
参数将包含子进程的 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
,当子进程运行时间超过 timeout
毫秒时,父进程将发送由 killSignal
属性标识的信号(默认值为 'SIGTERM'
)。
与 exec(3)
POSIX 系统调用不同,child_process.exec()
不会替换现有进程,而是使用 shell 执行命令。
如果此方法被调用为其 util.promisify()
版本,它将返回一个 Promise
,该 Promise
用于包含 stdout
和 stderr
属性的 Object
。返回的 ChildProcess
实例作为 child
属性附加到 Promise
。如果发生错误(包括导致非 0 退出代码的任何错误),将返回一个被拒绝的 promise,其中包含与回调中提供的相同 error
对象,但具有两个额外的属性 stdout
和 stderr
。
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> stdout 或 stderr 上允许的最大数据量(以字节为单位)。如果超过此限制,子进程将被终止,任何输出都将被截断。参见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> 允许使用 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);
});
传递给回调的 stdout
和 stderr
参数将包含子进程的 stdout 和 stderr 输出。默认情况下,Node.js 将以 UTF-8 解码输出并将字符串传递给回调。encoding
选项可用于指定用于解码 stdout 和 stderr 输出的字符编码。如果 encoding
为 'buffer'
或无法识别的字符编码,则将向回调传递 Buffer
对象。
如果此方法被调用为其 util.promisify()
版本,它将返回一个 Promise
,该 Promise
用于包含 stdout
和 stderr
属性的 Object
。返回的 ChildProcess
实例作为 child
属性附加到 Promise
。如果发生错误(包括导致非 0 退出代码的任何错误),将返回一个被拒绝的 promise,其中包含与回调中提供的相同 error
对象,但具有两个额外的属性 stdout
和 stderr
。
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> 允许使用 AbortSignal 关闭子进程。killSignal
<string> | <integer> 当生成的进程因超时或中止信号而被终止时,将使用的信号值。默认值:'SIGTERM'
。silent
<boolean> 如果为true
,则子进程的 stdin、stdout 和 stderr 将被管道传输到父进程,否则它们将从父进程继承,有关更多详细信息,请参见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
标识的文件描述符 (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
<Object>cwd
<string> | <URL> 子进程的当前工作目录。env
<Object> 环境键值对。默认值:process.env
。argv0
<string> 显式设置发送到子进程的argv[0]
的值。如果未指定,它将设置为command
。stdio
<Array> | <string> 子进程的 stdio 配置(请参阅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> 允许使用 AbortSignal 中止子进程。timeout
<number> 进程允许运行的最大时间(以毫秒为单位)。默认值:undefined
。killSignal
<string> | <integer> 当生成的进程因超时或中止信号而被终止时,将使用的信号值。默认值:'SIGTERM'
。
- 返回值: <ChildProcess>
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
的示例,捕获 stdout
、stderr
和退出代码
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]
不会与从父进程传递给 spawn
的 argv0
参数匹配。请使用 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 会重定向到 subprocess.stdin
、subprocess.stdout
和 subprocess.stderr
流上相应的 ChildProcess
对象。这等效于将 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 分别对应于标准输入、标准输出和标准错误。可以指定额外的文件描述符来在父进程和子进程之间创建额外的管道。该值可以是以下之一:
-
'pipe'
: 在子进程和父进程之间创建一个管道。管道的父端作为child_process
对象上的一个属性暴露给父进程,即subprocess.stdio[fd]
。为文件描述符 0、1 和 2 创建的管道也可以作为subprocess.stdin
、subprocess.stdout
和subprocess.stderr
使用,分别对应于标准输入、标准输出和标准错误。这些不是真正的 Unix 管道,因此子进程无法通过其描述符文件(例如/dev/fd/2
或/dev/stdout
)使用它们。 -
'overlapped'
: 与'pipe'
相同,只是在句柄上设置了FILE_FLAG_OVERLAPPED
标志。这对于子进程的标准输入/输出句柄上的重叠 I/O 是必需的。有关更多详细信息,请参见 文档。在非 Windows 系统上,这与'pipe'
完全相同。 -
'ipc'
: 创建一个 IPC 通道,用于在父进程和子进程之间传递消息/文件描述符。一个ChildProcess
最多可以有一个 IPC 标准输入/输出文件描述符。设置此选项将启用subprocess.send()
方法。如果子进程是 Node.js 进程,则 IPC 通道的存在将启用process.send()
和process.disconnect()
方法,以及子进程中的'disconnect'
和'message'
事件。除了
process.send()
之外,以任何其他方式访问 IPC 通道文件描述符,或者将 IPC 通道与不是 Node.js 实例的子进程一起使用,都是不支持的。 -
'ignore'
: 指示 Node.js 忽略子进程中的文件描述符。虽然 Node.js 始终会为其生成的进程打开文件描述符 0、1 和 2,但将文件描述符设置为'ignore'
将导致 Node.js 打开/dev/null
并将其附加到子进程的文件描述符。 -
'inherit'
: 将相应的标准输入/输出流传递到/从父进程。在前三个位置,这等同于process.stdin
、process.stdout
和process.stderr
,分别对应于标准输入、标准输出和标准错误。在任何其他位置,等同于'ignore'
。 -
<Stream> 对象:与子进程共享一个可读或可写的流,该流引用一个 tty、文件、套接字或管道。流的底层文件描述符在子进程中被复制到与
stdio
数组中索引相对应的 fd。流必须具有底层描述符(文件流在'open'
事件发生之前不会启动)。 -
正整数:整数值被解释为父进程中打开的文件描述符。它与子进程共享,类似于 <Stream> 对象的共享方式。在 Windows 上不支持传递套接字。
-
null
,undefined
:使用默认值。对于 stdio fd 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 进程时,子进程将使用未引用(使用 unref()
)的 IPC 通道启动,直到子进程为 'disconnect'
事件或 'message'
事件注册事件处理程序。这允许子进程正常退出,而不会因打开的 IPC 通道而保持进程打开。
同步进程创建#
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]
设置为'pipe'
,则提供此值将覆盖stdio[0]
。stdio
<string> | <Array> 子进程的标准输入输出配置。默认情况下,stderr
将输出到父进程的 stderr,除非指定了stdio
。默认值:'pipe'
。env
<Object> 环境键值对。默认值:process.env
。uid
<number> 设置进程的用户标识(参见setuid(2)
)。gid
<number> 设置进程的组标识(参见setgid(2)
)。timeout
<number> 进程允许运行的最大时间(以毫秒为单位)。默认值:undefined
。killSignal
<string> | <integer> 当生成的进程被杀死时要使用的信号值。默认值:'SIGTERM'
。maxBuffer
<number> 允许在 stdout 或 stderr 上的最大数据量(以字节为单位)。如果超过此限制,子进程将被终止。请参阅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> 命令的 stdout。
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]
设置为'pipe'
,则提供此值将覆盖stdio[0]
。stdio
<string> | <Array> 子进程的标准输入输出配置。默认情况下,stderr
将输出到父进程的 stderr,除非指定了stdio
。默认值:'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> stdout 或 stderr 上允许的最大数据量(以字节为单位)。如果超过此限制,子进程将被终止,任何输出都将被截断。参见maxBuffer
和 Unicode 处的注意事项。默认值:1024 * 1024
。encoding
<string> 用于所有标准输入输出的编码。默认值:'buffer'
。windowsHide
<boolean> 隐藏在 Windows 系统上通常会创建的子进程控制台窗口。默认值:false
。
- 返回值:<Buffer> | <string> 命令的 stdout。
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]
设置为'pipe'
,则提供此值将覆盖stdio[0]
。argv0
<string> 显式设置发送到子进程的argv[0]
的值。如果未指定,它将设置为command
。stdio
<string> | <Array> 子进程的 stdio 配置。默认值:'pipe'
。env
<Object> 环境键值对。默认值:process.env
。uid
<number> 设置进程的用户标识(参见setuid(2)
)。gid
<number> 设置进程的组标识(参见setgid(2)
)。timeout
<number> 进程允许运行的最大时间(以毫秒为单位)。默认值:undefined
。killSignal
<string> | <integer> 当生成的进程被杀死时要使用的信号值。默认值:'SIGTERM'
。maxBuffer
<number> stdout 或 stderr 上允许的最大数据量(以字节为单位)。如果超过此限制,子进程将被终止,任何输出都将被截断。参见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>
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'
#
'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'
#
在父进程中调用 subprocess.disconnect()
方法或在子进程中调用 process.disconnect()
方法后,将发出 'disconnect'
事件。断开连接后,将无法再发送或接收消息,并且 subprocess.connected
属性为 false
。
事件: 'error'
#
err
<Error> 错误。
当以下情况发生时,会触发 'error'
事件:
- 无法生成进程。
- 无法杀死进程。
- 向子进程发送消息失败。
- 子进程通过
signal
选项被中止。
在发生错误后,'exit'
事件可能会或可能不会触发。当同时监听 'exit'
和 'error'
事件时,请注意避免意外多次调用处理函数。
另请参阅 subprocess.kill()
和 subprocess.send()
。
事件: 'exit'
#
子进程结束时会触发 'exit'
事件。如果进程退出,code
为进程的最终退出代码,否则为 null
。如果进程因收到信号而终止,signal
为信号的字符串名称,否则为 null
。两者中总有一个不为 null
。
当 'exit'
事件触发时,子进程的标准输入输出流可能仍然处于打开状态。
Node.js 为 SIGINT
和 SIGTERM
建立信号处理程序,Node.js 进程不会因收到这些信号而立即终止。相反,Node.js 会执行一系列清理操作,然后重新引发已处理的信号。
请参阅 waitpid(2)
。
事件: 'message'
#
message
<Object> 解析后的 JSON 对象或原始值。sendHandle
<Handle> 一个net.Socket
或net.Server
对象,或 undefined。
当子进程使用 process.send()
发送消息时,会触发 'message'
事件。
消息会经过序列化和解析。最终的消息可能与最初发送的消息不同。
如果在生成子进程时将 serialization
选项设置为 'advanced'
,则 message
参数可以包含 JSON 无法表示的数据。有关详细信息,请参阅 高级序列化。
事件: 'spawn'
#
当子进程成功生成时,将发出 'spawn'
事件。如果子进程未成功生成,则不会发出 'spawn'
事件,而是发出 'error'
事件。
如果发出,'spawn'
事件将在所有其他事件之前以及通过 stdout
或 stderr
接收任何数据之前发生。
无论在生成的进程中是否发生错误,'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.connected
为 false
时,将无法再发送或接收消息。
subprocess.disconnect()
#
关闭父进程和子进程之间的 IPC 通道,允许子进程在没有其他连接使其保持活动状态的情况下优雅地退出。调用此方法后,父进程和子进程(分别)中的 subprocess.connected
和 process.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 中运行新进程或使用 ChildProcess
的 shell
选项时。
'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]()
#
使用 'SIGTERM'
调用 subprocess.kill()
。
subprocess.killed
#
- <布尔值> 在
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>- 返回值: <布尔值>
当在父进程和子进程之间建立了 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
。否则,该方法将返回 true
。callback
函数可用于实现流量控制。
示例:发送服务器对象#
例如,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
#
表示子进程 stderr
的 Readable Stream
。
如果子进程使用 stdio[2]
设置为除 'pipe'
之外的任何值启动,则这将为 null
。
subprocess.stderr
是 subprocess.stdio[2]
的别名。这两个属性将引用相同的值。
如果子进程无法成功启动,则 subprocess.stderr
属性可以为 null
或 undefined
。
subprocess.stdin
#
表示子进程 stdin
的 Writable Stream
。
如果子进程等待读取所有输入,则在通过 end()
关闭此流之前,子进程不会继续。
如果子进程使用 stdio[0]
设置为除 'pipe'
之外的任何值启动,则这将为 null
。
subprocess.stdin
是 subprocess.stdio[0]
的别名。这两个属性将引用相同的值。
如果子进程无法成功启动,则 subprocess.stdin
属性可以为 null
或 undefined
。
subprocess.stdio
#
一个稀疏数组,包含到子进程的管道,对应于传递给 child_process.spawn()
的 stdio
选项中已设置为值 'pipe'
的位置。subprocess.stdio[0]
、subprocess.stdio[1]
和 subprocess.stdio[2]
也分别可用作 subprocess.stdin
、subprocess.stdout
和 subprocess.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
#
表示子进程 stdout
的 可读流
。
如果子进程使用 stdio[1]
设置为除 'pipe'
之外的任何值,则此值将为 null
。
subprocess.stdout
是 subprocess.stdio[1]
的别名。这两个属性将引用相同的值。
const { spawn } = require('node:child_process');
const subprocess = spawn('ls');
subprocess.stdout.on('data', (data) => {
console.log(`Received chunk ${data}`);
});
如果无法成功生成子进程,则 subprocess.stdout
属性可能为 null
或 undefined
。
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
选项指定 stdout
或 stderr
上允许的最大字节数。如果超过此值,则子进程将被终止。这会影响包含多字节字符编码(如 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'
的路径,但子进程并不总是受相同要求的约束。因此,在 child_process
函数中,如果可以生成 shell,则如果 process.env.ComSpec
不可用,则使用 'cmd.exe'
作为后备。
高级序列化#
子进程支持一种基于 node:v8
模块的序列化 API 的 IPC 序列化机制,该机制基于 HTML 结构化克隆算法。这通常更强大,并支持更多内置 JavaScript 对象类型,例如 BigInt
、Map
和 Set
、ArrayBuffer
和 TypedArray
、Buffer
、Error
、RegExp
等。
但是,这种格式并非 JSON 的完整超集,例如,设置在这些内置类型对象上的属性不会通过序列化步骤传递。此外,根据传递数据的结构,性能可能与 JSON 不等效。因此,此功能需要通过在调用 child_process.spawn()
或 child_process.fork()
时将 serialization
选项设置为 'advanced'
来选择加入。