electron 主进程和渲染进程通信的三种方式及使用场景

在 Electron 中,send/onsendSyncinvoke/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 。主进程回复消息需要通过 return 的方式进行回复,而 ipcRenderer 只需要等到 Promise resolve 即可获取到返回的值。

三者对比总结

特性 send + on sendSync invoke + handle
同步性 异步 同步(阻塞渲染进程) 异步(Promise 回调)
返回值 无(单向通信) 有(通过 returnValue 有(通过 Promise
性能影响 无阻塞 可能导致 UI 卡顿 无阻塞
错误处理 需手动传递错误信息 难以处理复杂错误 支持 try/catchPromise.catch
适用场景 通知、事件广播 简单同步查询 异步操作、耗时任务
推荐程度 低(仅紧急情况)

最佳实践建议

  1. 优先使用 invoke:现代 Electron 开发的首选方式,性能最优。
  2. 避免 sendSync:除非必要(如简单配置查询),否则不要使用。
  3. send/on 用于单向通信:适用于事件通知或无需返回值的场景。
  4. 主进程向渲染进程回复(发松)消息:根据上面三个,都是基于event.reply,revent.returnvalue,return的方式,除此之外,也可以用 BrowserWindow.webContents.send

你可能感兴趣的:(electron)