在 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