进程间通信 (IPC)
在 Electron 中,主进程和渲染进程的隔离是架构的核心。它们不能直接共享内存或互相调用方法,必须通过进程间通信(IPC, Inter-Process Communication)来交互。这是 Electron 面试中最常考的知识点。
核心通信模块
ipcMain:只能在主进程中使用,用于接收渲染进程的消息,或者向渲染进程发送消息。ipcRenderer:只能在渲染进程(或 Preload 脚本)中使用,用于向主进程发送消息,或接收主进程的消息。
常见的通信模式
模式 1:渲染进程向主进程发送消息(单向)
比如渲染进程想要触发一个系统通知,不需要主进程返回结果。
- 发送方 (渲染进程):
ipcRenderer.send('channel', data) - 接收方 (主进程):
ipcMain.on('channel', (event, data) => {})
模式 2:渲染进程调用主进程并等待结果(双向/异步)
这是最常用的模式。比如渲染进程想读取本地文件,并等待读取到的内容返回。
推荐使用 Promise 风格的 invoke/handle API,而不是旧版的 send/on。
接收/处理方 (主进程):
ipcMain.handle('read-file', async (event, filePath) => {
const content = await fs.promises.readFile(filePath, 'utf-8');
return content; // 返回值将作为 Promise 的 resolve 结果
});调用方 (渲染进程):
async function getFile() {
const content = await ipcRenderer.invoke('read-file', '/path/to/file.txt');
console.log(content);
}
模式 3:主进程主动向渲染进程发送消息
通常用于系统层面的事件(如点击了系统托盘、定时器触发、硬件状态改变)需要通知前端页面刷新。
- 发送方 (主进程):必须先拿到目标窗口的实例
webContents。mainWindow.webContents.send('update-status', 'Network Disconnected'); - 接收方 (渲染进程):
ipcRenderer.on('update-status', (event, message) => {
console.log('Received from main:', message);
});
现代 Electron 的最佳实践:ContextBridge
面试考点:为什么不直接在 Vue/React 代码里
import { ipcRenderer } from 'electron'?
原因:安全问题。如果渲染进程直接拥有 Node.js 权限(nodeIntegration: true),一旦页面加载了恶意的第三方脚本(XSS攻击),黑客就能直接调用底层 API 控制用户的电脑。
正确做法:
- 主进程配置
nodeIntegration: false和contextIsolation: true。 - 在 Preload 脚本 中,使用
contextBridge.exposeInMainWorld将安全的 API 暴露给前端全局window对象。
// preload.js
const { contextBridge, ipcRenderer } = require('electron');
// 暴露一个名为 window.myAPI 的对象给前端
contextBridge.exposeInMainWorld('myAPI', {
readFile: (path) => ipcRenderer.invoke('read-file', path),
onUpdate: (callback) => ipcRenderer.on('update-status', (event, msg) => callback(msg))
});
// 前端代码 (Vue/React)
// 前端没有任何 electron 或 nodejs 的依赖,只能调用暴露出的受限接口
const content = await window.myAPI.readFile('/test.txt');