Node.js child_process 模块
Node.js 内置模块
Node.js 是一个单线程的 JavaScript 运行时环境,但有时候我们需要执行一些系统命令或运行其他程序。这时就需要用到 child_process 模块。
child_process 模块允许 Node.js 应用程序创建子进程,这些子进程可以执行系统命令、运行其他脚本或程序,并与父进程进行通信。
为什么需要 child_process?
执行系统命令:比如执行 ls、git 等命令行工具
运行 CPU 密集型任务:避免阻塞 Node.js 主线程
与其他语言编写的程序交互:比如调用 Python 或 C++ 程序
提高应用性能:通过多进程充分利用多核 CPU
创建子进程的四种方法
1. exec() - 执行简单命令
exec() 方法用于执行简单的 shell 命令,并缓冲输出结果。
实例
const { exec } = require('child_process');
exec('ls -l', (error, stdout, stderr) => {
if (error) {
console.error(`执行错误: ${error}`);
return;
}
console.log(`标准输出:\n${stdout}`);
if (stderr) {
console.error(`标准错误输出:\n${stderr}`);
}
});
特点:
适合执行简单的命令
返回完整的缓冲输出
有最大缓冲区限制(默认 200KB)
2. execFile() - 执行可执行文件
execFile() 类似于 exec(),但直接执行文件而不是通过 shell。
实例
const { execFile } = require('child_process');
execFile('node', ['--version'], (error, stdout, stderr) => {
if (error) {
throw error;
}
console.log(stdout);
});
特点:
比 exec() 更安全(不通过 shell)
执行效率更高
不能使用 shell 特性(如管道、通配符等)
3. spawn() - 流式处理子进程
spawn() 方法使用流式接口处理子进程的输入输出。
实例
const { spawn } = require('child_process');
const ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', (data) => {
console.log(`标准输出: ${data}`);
});
ls.stderr.on('data', (data) => {
console.error(`标准错误输出: ${data}`);
});
ls.on('close', (code) => {
console.log(`子进程退出码: ${code}`);
});
特点:
适合处理大量输出
流式处理,内存效率高
可以实时处理输出
4. fork() - 创建 Node.js 子进程
fork() 是 spawn() 的特例,专门用于创建新的 Node.js 进程。
实例
const { fork } = require('child_process');
const child = fork('child.js');
child.on('message', (msg) => {
console.log('来自子进程的消息:', msg);
});
child.send({ hello: 'world' });
特点:
创建新的 Node.js 实例
内置 IPC(进程间通信)通道
适合 CPU 密集型任务
进程间通信 (IPC)
父进程和子进程可以通过 send() 和 message 事件进行通信。
父进程 (parent.js):
实例
const { fork } = require('child_process');
const child = fork('child.js');
child.on('message', (msg) => {
console.log('父进程收到:', msg);
});
child.send({ parent: 'Hello from parent' });
子进程 (child.js):
实例
process.on('message', (msg) => {
console.log('子进程收到:', msg);
process.send({ child: 'Hello from child' });
});
错误处理
正确处理子进程错误非常重要:
实例
const { spawn } = require('child_process');
const child = spawn('some_command');
child.on('error', (err) => {
console.error('启动子进程失败:', err);
});
child.stderr.on('data', (data) => {
console.error(`子进程错误: ${data}`);
});
child.on('exit', (code, signal) => {
if (code) console.log(`子进程退出码: ${code}`);
if (signal) console.log(`子进程被信号终止: ${signal}`);
});
最佳实践
安全性:避免直接将用户输入传递给子进程
资源管理:及时清理已完成的子进程
错误处理:始终处理错误事件和退出事件
性能考虑:对于频繁创建的子进程,考虑使用进程池
跨平台兼容性:注意不同操作系统的命令差异
总结
child_process 模块是 Node.js 中处理子进程的核心模块,提供了四种创建子进程的方法:
exec() - 适合简单命令
execFile() - 适合执行可执行文件
spawn() - 适合流式处理
fork() - 适合创建 Node.js 子进程
根据具体需求选择合适的方法,并注意错误处理和资源管理,可以充分发挥 Node.js 的多进程能力。
Node.js 内置模块