子进程
child-process、fork、exec。
30 分钟
子进程
Node 主进程是 单线程 Event Loop。nodejs-advanced-essentials 的 CLI 通常单进程即可;当需要 跑 shell、隔离崩溃、复用多核(配合 cluster) 时用 node:child_process。
学习目标
- 选择
spawn、exec、execFile、fork的适用场景 - 处理 stdin/stdout/stderr 与退出码
- 理解
fork与 IPC 消息通道
四种启动方式
| 方法 | 特点 | 典型场景 |
|---|---|---|
spawn(cmd, args) | 流式 I/O,不缓冲全量输出 | 长跑命令、管道 |
exec(cmd) | 缓冲 stdout/stderr,有 maxBuffer 上限 | 短 shell 一行命令 |
execFile(file, args) | 不经过 shell,更安全 | 调用固定可执行文件 |
fork(modulePath) | Node 专用,自带 IPC | 子 Node 进程、cluster 基础 |
import { spawn } from "node:child_process";
const child = spawn("node", ["--version"], { stdio: "inherit" });
child.on("close", (code) => {
console.log("exit code:", code);
});
安全:避免 shell 注入
反模式:exec(git clone ${userInput})——用户输入可注入 ; rm -rf /。
推荐:spawn("git", ["clone", url], { shell: false }) 或 execFile 传数组参数。
与 nva-cli 解析 argv 同理:永远不要把未校验字符串拼进 shell。
fork 与 IPC
fork 启动子 Node 进程,并通过 send / message 传 JSON 可序列化对象:
import { fork } from "node:child_process";
if (process.send) {
// 子进程
process.on("message", (msg) => {
process.send({ ok: true, echo: msg });
});
} else {
const child = fork(new URL("./worker-child.js", import.meta.url));
child.on("message", (m) => console.log("from child:", m));
child.send({ task: "ping" });
}
大数据应用 流或 SharedArrayBuffer(见 nrt-worker),不要频繁传 MB 级对象。