child_process 子进程
源代码: lib/child_process.js
child_process
模块提供了以与 popen(3)
类似但不完全相同的方式衍生子进程的能力。
此功能主要由 child_process.spawn()
函数提供:
const { spawn } = require('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 进程和衍生的子进程之间建立 stdin
、stdout
和 stderr
的管道。
这些管道的容量有限(且特定于平台)。
如果子进程在没有捕获输出的情况下写入标准输出超过该限制,则子进程会阻塞等待管道缓冲区接受更多数据。
这与 shell 中管道的行为相同。
如果不消费输出,则使用 { stdio: 'ignore' }
选项。
如果在 options
对象中有 options.env.PATH
环境变量,则使用其执行命令查找。
否则,使用 process.env.PATH
。
在 Windows 上,环境变量不区分大小写。
Node.js 按字典顺序对 env
键进行排序,并使用不区分大小写匹配的第一个键。
只有第一个(按字典顺序)条目将传给子流程。
当传给 env
选项的对象具有多个相同键名的变体时(例如 PATH
和 Path
),在 Windows 上可能会导致出现问题。
child_process.spawn()
方法异步衍生子进程,不会阻塞 Node.js 事件循环。
child_process.spawnSync()
函数以同步方式提供等效的功能,其会阻塞事件循环,直到衍生的进程退出或终止。
为方便起见,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 脚本,同步的方法可能更方便。 但是,在许多情况下,由于在衍生的进程完成前会停止事件循环,同步方法会对性能产生重大影响。
Source Code: lib/child_process.js
The child_process
module provides the ability to spawn subprocesses in
a manner that is similar, but not identical, to popen(3)
. This capability
is primarily provided by the child_process.spawn()
function:
const { spawn } = require('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}`);
});
By default, pipes for stdin
, stdout
, and stderr
are established between
the parent Node.js process and the spawned subprocess. These pipes have
limited (and platform-specific) capacity. If the subprocess writes to
stdout in excess of that limit without the output being captured, the
subprocess blocks waiting for the pipe buffer to accept more data. This is
identical to the behavior of pipes in the shell. Use the { stdio: 'ignore' }
option if the output will not be consumed.
The command lookup is performed using the options.env.PATH
environment
variable if it is in the options
object. Otherwise, process.env.PATH
is
used.
On Windows, environment variables are case-insensitive. Node.js
lexicographically sorts the env
keys and uses the first one that
case-insensitively matches. Only first (in lexicographic order) entry will be
passed to the subprocess. This might lead to issues on Windows when passing
objects to the env
option that have multiple variants of the same key, such as
PATH
and Path
.
The child_process.spawn()
method spawns the child process asynchronously,
without blocking the Node.js event loop. The child_process.spawnSync()
function provides equivalent functionality in a synchronous manner that blocks
the event loop until the spawned process either exits or is terminated.
For convenience, the child_process
module provides a handful of synchronous
and asynchronous alternatives to child_process.spawn()
and
child_process.spawnSync()
. Each of these alternatives are implemented on
top of child_process.spawn()
or child_process.spawnSync()
.
child_process.exec()
: spawns a shell and runs a command within that shell, passing thestdout
andstderr
to a callback function when complete.child_process.execFile()
: similar tochild_process.exec()
except that it spawns the command directly without first spawning a shell by default.child_process.fork()
: spawns a new Node.js process and invokes a specified module with an IPC communication channel established that allows sending messages between parent and child.child_process.execSync()
: a synchronous version ofchild_process.exec()
that will block the Node.js event loop.child_process.execFileSync()
: a synchronous version ofchild_process.execFile()
that will block the Node.js event loop.
For certain use cases, such as automating shell scripts, the synchronous counterparts may be more convenient. In many cases, however, the synchronous methods can have significant impact on performance due to stalling the event loop while spawned processes complete.