概述
Node.js 基于单线程事件循环模型,------当遇到 CPU 密集型任务(如大规模数学计算、图像/视频处理、文件压缩等)时,单个线程会被阻塞,导致整个应用停滞不前,无法处理其他请求。
child_process
模块正是 Node.js 为我们提供的,用于跳出单线程限制、真正利用多核 CPU 性能的强大武器。它允许你创建并管理子进程,从而执行系统命令、运行其他脚本或可执行文件,实现并行处理。
简单来说,child_process
能够在 Node.js 程序中"开小号",让多个任务同时进行,极大地提升了程序的性能。
核心 API
child_process
模块提供了四种主要方法来创建子进,适用于不同的场景。
1. exec
:执行 Shell 命令
exec
方法用于执行一个 Shell 命令 。它会启动一个 Shell(如 /bin/sh on Unix,cmd.exe on Windows)来解析命令,这意味着你可以使用管道 |
、重定向 >
等 Shell 特性。
它的特点是缓冲输出 ,即会等待命令完全执行完毕,然后将所有输出一次性返回给你。
javascript
const { exec } = require('child_process');
// 执行 git status 命令
exec('git status', (error, stdout, stderr) => {
if (error) {
console.error(`执行出错: ${error.message}`);
return;
}
if (stderr) {
console.error(`标准错误: ${stderr}`);
return;
}
console.log(`标准输出: ${stdout}`);
});
适用场景
- 执行简单的、输出量不大的 Shell 命令,并获取最终结果。例如,获取项目
git
状态、检查磁盘空间 (df -h
) 等。
2. spawn
:流式处理
spawn
它不启动一个 Shell ,而是直接衍生一个新的进程 来执行指定的命令。它通过流(Stream) 的方式返回子进程的 stdout
和 stderr
。
这意味着你可以实时地接收到输出数据块,而不是等到命令结束。这对于处理大量数据(如处理大文件、长日志)至关重要,因为内存占用小,效率高。
javascript
const { spawn } = require('child_process');
// 使用 spawn 执行 find 命令,查找所有 .js 文件
const child = spawn('find', ['.', '-name', '*.js']);
// 实时接收数据
child.stdout.on('data', (data) => {
console.log(`找到文件: ${data}`);
});
child.stderr.on('data', (data) => {
console.error(`错误: ${data}`);
});
// 监听进程结束
child.on('close', (code) => {
console.log(`子进程退出,退出码: ${code}`);
});
适用场景:
- 处理大量输出 :如
npm install
、docker build
等需要实时查看进度的命令。
3. execFile
:二进制执行
execFile
与 exec
类似,但它不启动 Shell 。它直接执行一个可执行文件 。这使得它比 exec
效率稍高,而且更安全 (因为它避免了潜在的 Shell 注入攻击)。但它不能使用 Shell 的原语,如通配符 *
或管道 |
。
javascript
const { execFile } = require('child_process');
// 直接执行 node 可执行文件,并传递参数
execFile('node', ['--version'], (error, stdout, stderr) => {
if (error) {
throw error;
}
console.log(stdout); // v18.x.x
});
适用场景:运行已知的、不需要 Shell 特性的二进制文件或脚本,追求更高的安全性和效率。
总结
方法 | 核心特点 | 输出处理 | 典型使用场景 |
---|---|---|---|
exec |
使用 Shell | 缓冲 | 简单的 Shell 命令,输出量小 |
spawn |
不使用 Shell,高效 | 流式 (Stream) | 需要实时输出、处理大量数据 |
execFile |
不使用 Shell,安全 | 缓冲 | 执行已知的二进制可执行文件 |
上面的几个方法在项目工程化开发插件、提供开发工具、规范、文件输出、脚手架改造的时候比较常用。