Node.js Child Process 子程序:平行處理與外部指令執行
Node.js 雖然採用單執行緒 (Single-threaded) 的架構,但這並不代表它不能處理複雜的任務。透過 Child Process 模組,我們可以直接調用作業系統的資源來執行外部指令、運行腳本或進行多進程通訊,從而突破單核的限制。
執行簡單指令:exec 與 execFile
這是最常用的兩種執行方式,但它們在安全與用法上有細微差別:
1. exec(command, callback)
這是在一個 殼層 (Shell) 中執行指令。這意味著你可以使用 | (管線) 或 * (萬用字元)。
- 缺點:如果
command包含來自使用者的輸入,容易遭受 Shell Injection (殼層指令注入) 攻擊。
const { exec } = require('child_process');
exec('ls -lh', (err, stdout, stderr) => {
if (err) return console.error('執行失敗:', err);
console.log('檔案清單:\n', stdout);
});
2. execFile(file, args, callback)
不啟動 Shell,而是直接執行執行檔。參數以陣列形式傳入。
- 優點:效能更好且更安全。推薦在不需要 Shell 特性時使用。
處理大量數據:spawn
如果你要執行會產生海量數據的任務(例如影片轉檔 ffmpeg 或 ping 回應),exec 的 200KB 預設緩衝區會爆掉。此時必須使用 串流形式 的 spawn。
const { spawn } = require('child_process');
const ping = spawn('ping', ['google.com', '-c', '4']);
ping.stdout.on('data', (data) => {
console.log(`數據回報:${data}`);
});
ping.on('close', (code) => {
console.log(`子程序結束,結束代碼:${code}`);
});
Node 進階通訊:fork
fork 是專為兩個 Node.js 程序設計的通訊工具。它會建立一個內建的 IPC (Inter-Process Communication) 頻道。
// parent.js
const { fork } = require('child_process');
const worker = fork('worker.js');
worker.send({ task: 'compute' }); // 發送物件給子程序
worker.on('message', (result) => {
console.log('收到計算結果:', result);
});
應該選擇哪一個?
| 方法 | 核心特性 | 回傳方式 | 適用場景 |
|---|---|---|---|
exec | 在 Shell 中執行 | Callback (緩衝) | 簡單的一行腳本指令 |
execFile | 直接執行檔案 | Callback (緩衝) | 安全性要求高的外部程式調用 |
spawn | 串流式傳輸 | Stream | 大量數據處理(影音、Log) |
fork | Node 專屬通訊 | IPC | 將耗時計算移到另一個進程 |
重要提示:子程序是獨立的系統資源,開啟過多進程會劇烈消耗系統記憶體。如果你是為了優化 CPU 密集型的純 JS 計算(如圖片處理),現在更推薦使用 Worker Threads。
總結
- 追求安全與效能?首選
execFile。 - 處理大數據?務必用
spawn。 - 需要兩個 Node 程序互傳物件?請用
fork。