在 Electron 中,send/on、sendSync 和 invoke/handle 是三种不同的进程间通信 (IPC) 机制,它们的区别主要体现在同步性、API 设计和使用场景上。
与 Chromium 相同,Electron 使用进程间通信(IPC)来在进程之间进行通信:
- ipcMain 是一个仅在主进程中以异步方式工作的模块,用于与渲染进程交换消息。
- ipcRenderer 是一个仅在渲染进程中以异步方式工作的模块,用于与主进程交换消息。
以下是它们的详细对比:
1. send + on(异步通信)
特点
- 异步:发送消息后,主线程/渲染进程会继续执行,不会等待响应。
- 单向通信:通常用于通知或事件广播,不直接返回结果。
API 设计:
- 渲染进程 → 主进程:
ipcRenderer.send(channel, data) - 主进程 → 渲染进程:
webContents.send(channel, data) - 监听消息:
ipcMain.on(channel, (event, data) => { ... })
- 渲染进程 → 主进程:
适用场景
- 通知主进程执行操作(如打开文件、创建窗口)。
- 主进程向渲染进程推送实时数据(如系统事件、网络状态)。
- 不需要返回值的场景(如日志记录、状态更新)。
示例
// 渲染进程
ipcRenderer.send('open-file-dialog', '请选择文件');
// 主进程
ipcMain.on('open-file-dialog', (event, arg) => {
// 执行文件选择逻辑,不直接返回结果
});2. sendSync(同步通信)
特点
- 同步:发送消息后,渲染进程会阻塞直到主进程返回结果。
- 直接返回值:通过
event.returnValue传递结果。 API 设计:
- 渲染进程:
ipcRenderer.sendSync(channel, data) - 主进程:
ipcMain.on(channel, (event, data) => { event.returnValue = ... })
- 渲染进程:
适用场景
- 需要立即获取结果的简单操作(如读取配置、获取系统信息)。
- 不涉及耗时操作(如网络请求、文件读写)。
注意事项
- 性能问题:阻塞渲染进程会导致 UI 卡顿,Electron 官方不推荐在生产环境使用。
- 安全风险:同步调用可能导致死锁或意外阻塞。
示例
// 渲染进程
const result = ipcRenderer.sendSync('get-config', 'theme');
// 主进程
ipcMain.on('get-config', (event, key) => {
event.returnValue = config[key];
});注意,渲染进程通过 ipcRenderer.sendSync 发送消息后,主进程回复消息需要通过 e.returnValue 的方式进行回复,如果 event.returnValue 不为 undefined 的话,渲染进程会等待 sendSync 的返回值才执行后面的代码。
3. invoke + handle(异步通信 + 回调)
特点
- 异步:发送消息后,主线程/渲染进程继续执行。
- Promise 回调:通过
Promise获取异步结果,支持async/await。 API 设计:
- 渲染进程:
ipcRenderer.invoke(channel, data).then(result => { ... }) - 主进程:
ipcMain.handle(channel, async (event, data) => { return ... })
- 渲染进程:
适用场景
- 涉及耗时操作(如网络请求、文件读写)。
- 需要返回值,但不希望阻塞 UI。
- 复杂的异步逻辑(如多步骤操作、错误处理)。
示例
// 渲染进程
ipcRenderer.invoke('fetch-data', url)
.then(data => {
// 处理返回的数据
})
.catch(err => {
// 处理错误
});
// 主进程
ipcMain.handle('fetch-data', async (event, url) => {
const response = await fetch(url);
return response.json();
});注意,渲染进程通过 ipcRenderer.invoke 发送消息后,invoke 的返回值是一个 Promise<pending> 。主进程回复消息需要通过 return 的方式进行回复,而 ipcRenderer 只需要等到 Promise resolve 即可获取到返回的值。
三者对比总结
| 特性 | send + on | sendSync | invoke + handle |
|---|---|---|---|
| 同步性 | 异步 | 同步(阻塞渲染进程) | 异步(Promise 回调) |
| 返回值 | 无(单向通信) | 有(通过 returnValue) | 有(通过 Promise) |
| 性能影响 | 无阻塞 | 可能导致 UI 卡顿 | 无阻塞 |
| 错误处理 | 需手动传递错误信息 | 难以处理复杂错误 | 支持 try/catch 和 Promise.catch |
| 适用场景 | 通知、事件广播 | 简单同步查询 | 异步操作、耗时任务 |
| 推荐程度 | 高 | 低(仅紧急情况) | 高 |
最佳实践建议
- 优先使用
invoke:现代 Electron 开发的首选方式,性能最优。 - 避免
sendSync:除非必要(如简单配置查询),否则不要使用。 send/on用于单向通信:适用于事件通知或无需返回值的场景。- 主进程向渲染进程回复(发松)消息:根据上面三个,都是基于
event.reply,revent.returnvalue,return的方式,除此之外,也可以用BrowserWindow.webContents.send
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。