child_process.fork() 是 Node.js/Electron 中专门用于创建 Node.js 子进程的方法,它基于 spawn() 但针对 Node.js 进程进行了优化,内置了进程间通信(IPC)通道。
一、fork() 的核心功能
- 专用 Node.js 进程:只能用于启动 Node.js 脚本(.js 文件)
- 内置 IPC 通道:自动建立父子进程间的通信通道
- 高效数据传输:支持发送 JavaScript 对象(序列化/反序列化)
- 内存隔离:子进程有独立的内存空间和 V8 实例
- 模块继承:子进程继承父进程的模块系统
二、方法签名
const { fork } = require('child_process');
const child = fork(modulePath[, args][, options]);
三、参数详解
1. modulePath (必需)
要运行的 Node.js 模块路径(相对于当前工作目录)
2. args (可选)
传递给子进程的参数数组
3. options (可选)
配置对象,特殊选项(除常规 spawn 选项外):
| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
execPath |
string | process.execPath | 用于创建子进程的 Node.js 可执行文件路径 |
execArgv |
Array | process.execArgv | 传递给 Node.js 可执行文件的参数 |
silent |
boolean | false | 是否不继承父进程的 stdio |
serialization |
string | 'json' | 进程间通信的序列化方法 ('json' 或 'advanced') |
四、使用注意事项
1. 安全性考虑
- 路径安全:永远使用
path.join()构造绝对路径
// 错误做法
fork(`./workers/${userInput}.js`);
// 正确做法
const safePath = path.join(__dirname, 'workers', 'predefined-worker.js');
fork(safePath);
- IPC 过滤:验证所有接收的消息
child.on('message', (msg) => {
if (msg.type && ALLOWED_TYPES.includes(msg.type)) {
// 处理消息
}
});
2. 资源管理
- 内存泄漏:定期重启长时间运行的子进程
- 进程限制:避免无限制创建子进程
const MAX_WORKERS = require('os').cpus().length;
const activeWorkers = new Set();
function createWorker() {
if (activeWorkers.size >= MAX_WORKERS) {
throw new Error('Worker limit reached');
}
const worker = fork(path.join(__dirname, 'worker.js'));
activeWorkers.add(worker);
worker.on('exit', () => activeWorkers.delete(worker));
return worker;
}
3. 错误处理
- 全面捕获:处理所有可能的错误事件
child.on('error', (err) => {
console.error('Process error:', err);
});
child.on('exit', (code, signal) => {
if (code !== 0) {
console.error(`Process exited abnormally with code ${code}`);}
});
process.on('uncaughtException', (err) => {
console.error('Uncaught exception in worker:', err);
});
五、完整用法示例
前置条件
-
需要在module.json5中添加JIT权限,否则会出现fork时crash现象

基础示例:简单进程创建
主进程 (main.js):
const { app, BrowserWindow, ipcMain, Tray, nativeImage } = require('electron');
const { fork } = require('child_process');
const path = require('path');
let mainWindow, tray;
function createWindow() {
tray = new Tray(nativeImage.createFromPath(path.join(__dirname, 'electron_white.png')));
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
}
});
console.log('electron-demo start');
mainWindow.loadFile('index.html');
}
app.whenReady().then(() => {
createWindow();
app.on('activate',() => {
if(BrowserWindow.getAllWindow().length === 0) createWindow();
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit();
});
});
// fork
console.log('electron-demo 即将开始fork!' + __dirname);
const child = fork(path.join(__dirname,'child.js'));
child.on('message',(message) => {
console.log('electron-demo 主进程收到消息',message);
console.log('child.connected: ', child.connected);
});
child.send({helo:'electron-demo from main process'});
// 在一段时间后关闭IPC通道
setTimeout(() => {
console.log('electron-demo Parent: disconnecting IPC...');
child.disconnect(); // 显式关闭IPC通道
}, 3000);
// 监听'disconnect'事件
child.on('disconnect', () => {
console.log('electron-demo Parent: IPC disconnected.');
console.log('electron-demo child.connected: ', child.connected);
console.log('electron-demo child.exitCode: ', child.exitCode)
});
child.on('exit', (code) => {
console.log(`electron-demo Child process exited with code ${code}`)
})
子进程 (child.js):
process.on('message',(message) => {
console.log('子进程收到消息:',message);
process.send({hello:'electron-demo from child process',received:message});
process.send({status:'electron-demo child process started'});
})
运行效果


实际应用:CPU 密集型任务
主进程:
const { app, BrowserWindow, ipcMain, Tray, nativeImage } = require('electron');
const { fork } = require('child_process');
const path = require('path');
let mainWindow, tray;
function createWindow() {
tray = new Tray(nativeImage.createFromPath(path.join(__dirname, 'electron_white.png')));
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
}
});
console.log('electron-demo start');
mainWindow.loadFile('index.html');
}
app.whenReady().then(() => {
createWindow();
app.on('activate',() => {
if(BrowserWindow.getAllWindow().length === 0) createWindow();
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit();
});
});
// fork
console.log('electron-demo 即将开始fork!' + __dirname);
const child = fork(path.join(__dirname,'fibonacci-worker.js'));
// 发送计算任务
child.send({ number: 40 });
child.on('message', (result) => {
console.log(`Fibonacci result: ${result.value}`);
child.kill(); // 任务完成后终止子进程
});
child.on('error', (err) => {
console.error('Worker error:', err);
});
fibonacci-worker.js:
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
process.on('message', ({ number }) => {
const result = fibonacci(number);
process.send({ value: result });
});
运行效果


高级示例:进程池管理
process-pool.js:
const { fork } = require('child_process');
const os = require('os');
class ProcessPool {
constructor(modulePath, size = os.cpus().length) {
this.pool = [];
this.queue = [];
this.maxSize = size;
this.modulePath = modulePath;
for (let i = 0; i < size; i++) {
this.createWorker();
}
}
createWorker() {
const worker = fork(this.modulePath);
worker.busy = false;
worker.on('message', (result) => {
worker.busy = false;
const callback = this.queue.shift();
if (callback) {
this.runTask(callback.task, callback.resolve, callback.reject);
}
});
this.pool.push(worker);
return worker;
}
runTask(task, resolve, reject) {
const availableWorker = this.pool.find(w => !w.busy);
if (availableWorker) {
availableWorker.busy = true;
availableWorker.send(task);
availableWorker.once('message', resolve);
availableWorker.once('error', reject);
} else if (this.pool.length < this.maxSize) {
const newWorker = this.createWorker();
this.runTask(task, resolve, reject);
} else {
this.queue.push({ task, resolve, reject });
}
}
execute(task) {
return new Promise((resolve, reject) => {
this.runTask(task, resolve, reject);
});
}
}
module.exports = ProcessPool;
六、高级配置技巧
1. 定制 Node.js 执行环境
const child = fork(path.join(__dirname, 'worker.js'), [], {
execPath: '/usr/local/bin/node', // 指定 Node.js 路径
execArgv: ['--inspect=9229'] // 启用子进程调试
});
2. 静默模式(不继承 stdio)
const child = fork(path.join(__dirname, 'worker.js'), [], {
silent: true // 子进程不会继承父进程的 stdio
});
// 手动处理输出
child.stdout.on('data', (data) => {
console.log('Worker stdout:', data.toString());
});
child.stderr.on('data', (data) => {
console.error('Worker stderr:', data.toString());
});
3. 高级序列化(Node.js v13.2.0+)
const child = fork(path.join(__dirname, 'worker.js'), [], {
serialization: 'advanced' // 支持更多 JS 类型
});
// 可以发送特殊对象
child.send({
date: new Date(),
set: new Set([1, 2, 3]),
map: new Map([['key', 'value']])
});
七、与 Electron 集成的特殊考虑
- 渲染进程中使用
- renderer.js
// 渲染进程 (renderer.js)
document.getElementById('start-btn').addEventListener('click', async () => {
const input = document.getElementById('input-data').value
const resultDiv = document.getElementById('result')
resultDiv.textContent = 'Processing...'
try {
// 调用主进程
await window.electronAPI.startTask(input)
// 设置回复监听
window.electronAPI.onWorkerReply((result) => {
resultDiv.textContent = `Result: ${result}`
})
} catch (error) {
resultDiv.textContent = `Error: ${error.message}`
}
})
- main.js
const { app, BrowserWindow, ipcMain, Tray, nativeImage } = require('electron');
const { fork } = require('child_process');
const path = require('path');
let mainWindow, tray, workerProcess;
function createWindow() {
tray = new Tray(nativeImage.createFromPath(path.join(__dirname, 'electron_white.png')));
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: path.join(__dirname, 'preload.js')
}
});
console.log('electron-demo start');
mainWindow.loadFile('index.html');
}
app.whenReady().then(() => {
createWindow();
// 创建 worker 进程
workerProcess = fork(path.join(__dirname, 'worker.js'))
// 监听来自 worker 的消息
process.on('message', (message) => {
console.log('Main process received from worker:', message)
mainWindow.webContents.send('worker-reply', message)
})
console.log('---------------------> register start-task')
// 监听渲染进程的请求
ipcMain.handle('start-task', (event, data) => {
console.log('Main process received from renderer:', data)
workerProcess.send({
type: 'compute',
data: data
})
})
// 处理worker上报消息
workerProcess.on('message',(message) => {
console.log('electron-demo 主进程收到消息', message.result);
// 将数据发送到渲染进程
mainWindow.webContents.send('worker-reply', message.result);
})
// 处理子进程退出
workerProcess.on('exit', (code) => {
console.log(`Worker process exited with code ${code}`)
})
app.on('activate',() => {
if(BrowserWindow.getAllWindow().length === 0) createWindow();
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit();
});
});
- preload.js
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
startTask: (data) => ipcRenderer.invoke('start-task', data),
onWorkerReply: (callback) => {
ipcRenderer.on('worker-reply', (_event, value) => callback(value))
}
})
- worker.js
process.on('message', (message) => {
console.log('Worker received task:', message.data)
if (message.type === 'compute') {
console.log('Worker compute:', message.data)
// 模拟耗时计算
const start = Date.now()
let result = heavyComputation(message.data)
const duration = Date.now() - start
// 发送结果回主进程
process.send({
input: message.data,
result: result,
duration: duration
})
}
})
function heavyComputation(input) {
// 模拟 CPU 密集型任务
let result = 0
for (let i = 0; i < 10; i++) {
result += Math.sqrt(i) * Math.sin(i) * input.length
}
return result
}
- index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Electron Fork Example</title>
<style>
body { font-family: Arial; padding: 20px; }
input { padding: 8px; width: 200px; }
button { padding: 8px 16px; margin-left: 10px; }
#result { margin-top: 20px; padding: 10px; background: #f0f0f0; }
</style>
</head>
<body>
<h1>Electron Fork Example</h1>
<div>
<input type="text" id="input-data" placeholder="Enter some data">
<button id="start-btn">Start Task</button>
</div>
<div id="result">Ready...</div>
<script src="renderer.js"></script>
</body>
</html>
-
运行效果展示


- 开发与生产环境路径处理
const { app } = require('electron');
const path = require('path');
function getWorkerPath() {
if (app.isPackaged) {
return path.join(process.resourcesPath, 'app.asar.unpacked', 'workers', 'worker.js');
}
return path.join(__dirname, 'workers', 'worker.js');
}
const worker = fork(getWorkerPath());
- 安全最佳实践
// 在主进程中创建白名单
const ALLOWED_WORKERS = {
'image-processor': './workers/image-processor.js',
'data-cruncher': './workers/data-cruncher.js'
};
ipcMain.handle('start-worker', (event, { workerName, task }) => {
if (!ALLOWED_WORKERS[workerName]) {
throw new Error('Unauthorized worker request');
}
return new Promise((resolve, reject) => {
const worker = fork(ALLOWED_WORKERS[workerName]);
worker.send(task);
worker.on('message', resolve);
worker.on('error', reject);
});
});
八、常见问题解决方案
-
消息丢失问题
- 确保在发送消息前子进程已准备好
- 使用
child.on('message', handler)前先设置
-
进程不退出
// 确保关闭所有 IPC 通道 child.disconnect(); // 必要时强制终止 child.kill(); -
内存泄漏
- 定期重启长时间运行的 worker
- 使用
child.unref()让子进程独立运行
-
调试技巧
const child = fork(path.join(__dirname, 'worker.js'), [], { execArgv: ['--inspect-brk=9229'] // 暂停等待调试器连接 });
通过以上详细介绍,您应该能够全面掌握 Electron 中 child_process.fork() 的使用方法,包括其核心功能、各种用法示例、测试验证方法以及在实际 Electron 项目中的应用技巧。