Node.js 中 exec、fork 和 spawn 的区别是什么?
Node.js 中 exec 用于执行 shell 命令,fork 启动子进程运行 Node.js 脚本,而 spawn 创建新进程来运行可执行文件。它们各自有不同的数据传输机制和通信能力。
exec
,fork
和 spawn
是 Node.js 的 child_process
模块用来创建子进程的方法,各有不同的机制和使用场景。区别主要在进程创建方式、数据传输机制、通信能力和适用性上。
exec
- 用途:执行 shell 命令字符串(如
echo "hello" | grep h
),在新启动的 shell 进程中运行命令。 - 核心特性:
- 使用缓冲区收集所有输出(stdout 和 stderr),通过回调一次性返回给父进程。
- 输出量默认可达 200KB;超出会导致错误,不建议处理大数据。
- 可设置 timeout 超时值,超时自动终止子进程。
- 优点: 适合快速的小批量命令操作,需要等待完整输出场景。
- 语法举例:
const { exec } = require('child_process'); exec('ls -l', { timeout: 3000 }, (error, stdout, stderr) => { if (error) { console.error(`错误输出: ${error}`); return; } console.log(stdout); });
spawn
- 用途: 直接启动新进程运行可执行文件或程序(如二进制文件或
.js
文件),不依赖 shell。 - 核心特性:
- 使用流(
stdin
,stdout
,stderr
)逐步交互数据,支持实时流输入/输出。 - 无输出数据大小限制;适合大数据量场景(如处理文件或长时间输出)。
- 不支持内置 IPC 通信(父子进程需自定义协议处理消息),也不提供 timeout。
- 是所有衍生基础;底层实现用于任意外部程序(甚至可运行
python script.py
)。
- 使用流(
- 优点: 高效的流式操作;适用于大流量、低延迟任务(如数据库导出或实时日志)。
- 语法举例:
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}`); });
fork
- 用途: 专门启动另一 Node.js 脚本,便于分离运行 JavaScript 代码及通信。
- 核心特性:
- 基于
spawn
实现:等同于spawn('node', [scriptPath])
,但自动建立双工 IPC通道用于通信。 - 支持父子进程消息传递:子进程通过
process.on('message', fn)
监听和process.send(data)
发送 JSON-serializable 对象。 - 数据可流但无限制;IPC channel允许灵活状态通信(如集群架构中 worker 任务同步)。
- 基于
- 优点: 内建 IPC 优势;适合分离复杂逻辑的任务线程(如Web服务器集群或实时多节点任务)。
- 语法举例:
父进程文件:
const { fork } = require('child_process'); const child = fork('./worker.js'); child.on('message', (msg) => { console.log(`父接收: ${msg.data}`); }); child.send({ command: 'start', count: 5 }); // JSON对象发送
子进程 (
worker.js
):process.on('message', (msg) => { console.log(`子收到: ${msg.command}`); process.send({ data: `处理完毕: ${msg.count}` }); // 回复消息 });
主要区别总结
- 数据传输机制:
spawn
和fork
使用流,处理无限制数据的实时输入输出;exec
通过内存缓冲区存储完整静态输出;仅限 <=200KB。
- 通信能力:
fork
内置专用于 JSON结构的 IPC(支持父子消息传递)。spawn
需自定义流协议;exec
无内置通信模式。
- 启动对象差异:
fork
: 唯一支持 Node.js脚本作为独立JavaScript 实例运行的子进程;spawn
: 支持任意可执行程序作为子进程(包括系统命令或 .js 文件须指定 node 命令作为入口);exec
: 指定字符串形式的完整 shell命令;不适合运行.js
文件脚本或二进制直接文件操作。
- 其它特性:
exec
和衍生execFile
有可设超时可调参数 timeout,自动停止长期进程;spawn
及 fork 中无 timeout内建特性,父进程必须主动管理终止(如 kill或时间控制函数显式判断响应超时状态)。- fork 操作可重用Node.js共享 V8 实例;比单独创建新节点进程资源开销稍高。
应⽤选择指南
- 在
Node.js
场景: 需执行另一 .js脚本并频繁数据消息时用fork
。 - 大流量外部程序/无固定数据边界场景: 适用
spawn
进行灵活流控处理。 - 简短的 shell命令仅作查询一次性回调时优先
exec
。
实际开发中多数函数逻辑基于 spawn底层机制调用选参数格式优化选择任务。