Node.js child_process 模块

Node.js child_process 模块

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 内置模块