Electron 主进程和渲染进程通信方法总结
Electron
主进程和渲染进程通信
一、主进程(IPCMain
)
方法名称 | 参数 | 类型 | 作用 | 典型使用场景 | 配套的渲染进程方法或说明 |
---|---|---|---|---|---|
on(channel, listener) | channel:string listener:回调函数 + Event + 参数 | 监听方法 | 监听渲染进程发送的异步消息;通过 event 参数可对消息做回复 | 接收渲染进程通过 send、sendSync 等发送的消息,如指令、通知 | 渲染进程使用 ipcRenderer.send 或 sendSync 发送消息 |
off(channel, listener) | channel:string listener:回调函数 + Event + 参数 | 监听移除方法 | 移除已注册的监听器 | 清理不再需要的消息监听 | — |
once(channel, listener) | channel:string listener:回调函数 + Event + 参数 | 一次性监听方法 | 监听一次性消息,触发后自动移除 | 仅需要响应一次的请求或事件,如初始化、一次性设置 | 与渲染进程的 once 配合使用 |
addListener(channel, listener) | channel:string listener:回调函数 + Event + 参数 | 监听方法的别名 | 与 on 功能一致 | — | — |
removeListener(channel, listener) | channel:string listener:回调函数 + Event + 参数 | 监听移除方法 | 移除指定的监听器 | — | — |
removeAllListeners(channel) | channel:string | 监听移除方法 | 移除某个通道上所有监听器 | 清理监听器,避免内存泄漏等 | — |
handle(channel, asyncListener) | channel:string listener:异步回调函数:Function<Promise any> + Event + 参数 | 异步请求处理方法 | 注册一个处理函数,用于响应渲染进程使用 invoke 发出的请求,并返回 Promise | 处理需要返回数据的异步任务,如读取文件、数据库操作、复杂计算 | 渲染进程使用 ipcRenderer.invoke 发起请求 |
handleOnce(channel, asyncListener) | channel:string listener:异步回调函数:Function<Promise any> + Event + 参数 | 一次性请求处理方法 | 注册一个只处理一次的异步请求处理函数 | 处理只需响应一次的异步请求(类似于 once 的行为) | 渲染进程使用 ipcRenderer.invoke 发起请求 |
removeHandler(channel) | channel:string | 请求处理移除方法 | 移除之前通过 handle 或 handleOnce 注册的处理函数 | 当需要动态注销或更新处理函数时使用 | — |
二、渲染进程(IPCRenderer
)
方法名称 | 参数 | 类型 | 作用 | 典型使用场景 | 配套的主进程方法或说明 |
---|---|---|---|---|---|
on(channel, listener) | channel:string listener:回调函数 + Event + 参数 | 监听方法 | 注册一个持续监听器,用于接收主进程推送的异步消息 | 需要不断接收主进程发送的更新、通知、状态改变等事件 | 主进程使用 webContents.send 或 event.reply 发送消息 |
off(channel, listener) | channel:string listener:回调函数 + Event + 参数 | 监听移除方法 | 移除先前通过 on 或 addListener 注册的监听器 | 组件卸载、取消不再需要的监听时使用 | — |
once(channel, listener) | channel:string listener:回调函数 + Event + 参数 | 一次性监听方法 | 注册一个只触发一次的监听器,接收到消息后自动移除 | 仅需响应一次的事件,如初始化数据或一次性通知 | 同上(发送消息方式与 on 相同) |
addListener(channel, listener) | channel:string listener:回调函数 + Event + 参数 | 监听方法的别名 | 与 on 功能相同,注册事件监听器 | 同 on | — |
removeListener(channel, listener) | channel:string listener:回调函数 + Event + 参数 | 监听移除方法 | 移除指定的监听器 | 当不再需要某个特定回调时使用 | — |
removeAllListeners(channel) | channel:string | 监听移除方法 | 移除某个通道上所有的监听器 | 清理某个频道的所有监听(例如切换页面或销毁窗口时) | — |
send(channel, …args) | channel:string …args:参数 | 异步发送方法 | 发送一个异步消息到主进程,消息发送后不等待返回值 | 火箭式通知,适用于不需要返回结果的指令或状态通知(如记录日志、触发动作) | 主进程通过 ipcMain.on 接收;可通过 event.reply 回传回复(可选) |
invoke(channel, …args) | channel:string …args:参数 | 异步请求方法(RPC) | 发送一个异步请求到主进程,并返回一个 Promise,可等待主进程返回数据 | 需要主进程处理后返回结果的场景,如文件操作、数据库查询、长耗时任务等 | 主进程使用 ipcMain.handle 或 handleOnce 注册处理函数 |
sendSync(channel, …args) | channel:string …args:参数 | 同步发送方法 | 同步发送消息到主进程,并等待返回结果(会阻塞渲染进程) | 简单、快速的操作需要立即返回结果时使用;注意:可能阻塞 UI,不推荐耗时任务 | 主进程通过 ipcMain.on 接收,需在监听器中设置 event.returnValue |
postMessage(channel, message, transfer?) | channel: string message: 任意数据 transfer 消息端口[] | 消息传递方法 | 通过 MessagePort 机制发送消息(在 contextIsolation 环境下) | 使用嵌入式 Webview 或在特殊场景下需要使用 MessagePort 进行通信时使用 | 与 window.postMessage 类似,主要用于多上下文通信 |
sendToHost(channel, …args) | channel:string …args:参数 | 特殊发送方法 | 从嵌入的 Webview 中将消息发送给宿主页面(Host) | 当 Webview 内容需要通知宿主页面某个事件或状态时使用 | 宿主页面通过 ipcRenderer.on(或 Webview 提供的事件)接收 |
三、使用场景和作用总结
1. 消息发送(send / sendSync / postMessage / sendToHost
)
send
- 作用:异步发送消息,不等待返回;适用于单向通知。
- 场景:渲染进程通知主进程执行某操作(如保存日志、触发事件)。
- 配套:主进程通过 on 监听,必要时用 event.reply 回传数据。
1.1. sendSync
- 作用:同步发送消息,并阻塞等待返回。
- 场景:当需要立刻获得一个简单结果(例如读取配置)时使用,但容易阻塞界面,不推荐用于耗时任务。
- 配套:主进程在监听器中通过设置 event.returnValue 返回数据。
1.2. postMessage
- 作用:通过 MessagePort 发送消息,通常在隔离上下文中使用。
- 场景:在启用了 contextIsolation 或需要使用 MessageChannel 的场景下,特别适用于 Webview 与宿主间的通信。
- 配套:基于 window.postMessage 的消息接收方式。
1.3. sendToHost
- 作用:专为 Webview 内部内容向宿主页面发送消息设计。
- 场景:嵌入的 Webview 需要向其宿主页面报告状态或事件时使用。
- 配套:宿主页面监听相应的事件。
2. 请求/响应通信(invoke / handle / handleOnce / removeHandler
)
2.1. invoke
- 作用:以异步(RPC 风格)发送请求,并返回一个 Promise;避免了回调地狱,代码更简洁。
- 场景:渲染进程需要请求主进程执行操作并等待结果(如文件操作、数据库查询、耗时任务处理)。
- 配套:主进程使用 handle 或 handleOnce 注册处理函数,返回处理结果。
2.2. handle / handleOnce
- 作用:在主进程中注册一个异步处理函数,响应渲染进程发出的 invoke 请求。
- 场景:处理涉及异步操作的请求,handleOnce 用于仅需响应一次的情况。
- 配套:渲染进程使用 invoke 发起请求。
2.3. removeHandler
- 作用:移除已经注册的处理函数,便于动态更新或清理。
- 场景:在应用生命周期中需要更新或取消某些 IPC 处理逻辑时使用。
2.4. 监听接收消息(on / once / addListener / off / removeListener / removeAllListeners
)
on / addListener
- 作用:在渲染进程或主进程注册持续监听器,用于接收对方发送的消息。
- 场景:持续监听状态更新、事件通知或其他异步消息。
2.5. once
- 作用:注册一次性监听器,接收一次消息后自动解除注册。
- 场景:只需处理一次的事件,如首次数据加载或一次性通知。
2.6. off / removeListener / removeAllListeners
- 作用:取消注册一个或所有监听器,防止内存泄漏或避免重复响应。
- 场景:组件卸载、需要清理监听器时使用。
四、方法示例
1. 暴露到 window
中
为了方便我们可以先把 ipcRenderer
暴露到 window
中,方便使用
import { contextBridge, ipcRenderer } from 'electron'contextBridge.exposeInMainWorld('electronAPI', {on: ipcRenderer.on.bind(ipcRenderer),off: ipcRenderer.off.bind(ipcRenderer),once: ipcRenderer.once.bind(ipcRenderer),addListener: ipcRenderer.addListener.bind(ipcRenderer),removeListener: ipcRenderer.removeListener.bind(ipcRenderer),removeAllListeners: ipcRenderer.removeAllListeners.bind(ipcRenderer),send: ipcRenderer.send.bind(ipcRenderer),invoke: ipcRenderer.invoke.bind(ipcRenderer),sendSync: ipcRenderer.sendSync.bind(ipcRenderer),postMessage: ipcRenderer.postMessage.bind(ipcRenderer),sendToHost: ipcRenderer.sendToHost ? ipcRenderer.sendToHost.bind(ipcRenderer) : undefined
});
2. ipcMain
主进程
/* 主进程 IPC 方法示例 */
import { app, BrowserWindow, ipcMain } from 'electron';// 1. on:监听渲染进程通过 send 或 sendSync 发送的消息
ipcMain.on('example-send', (event, arg) => {console.log('[Main] on: Received "example-send":', arg);// 可通过 event.reply 回复event.reply('example-reply', 'Hello from main (reply via on)');
});// 2. once:一次性监听,只响应一次
ipcMain.once('example-once', (event, arg) => {console.log('[Main] once: Received "example-once":', arg);
});// 3. addListener:与 on 别名相同,监听消息
ipcMain.addListener('example-addListener', (event, arg) => {console.log('[Main] addListener: Received "example-addListener":', arg);
});// 4. off / removeListener:注册监听器后移除指定回调
function mainOffListener(event, arg) {console.log('[Main] off/removeListener: Listener triggered:', arg);
}
ipcMain.on('example-off', mainOffListener);
// 移除监听器:
ipcMain.off('example-off', mainOffListener);// 5. removeAllListeners:移除指定通道的所有监听器
ipcMain.on('example-removeAll', (event, arg) => {console.log('[Main] This should be removed:', arg);
});
ipcMain.removeAllListeners('example-removeAll');// 6. sendSync:处理同步消息
ipcMain.on('example-sendSync', (event, arg) => {console.log('[Main] sendSync: Received:', arg);// 设置返回值,sendSync 调用会接收到此值event.returnValue = 'Hello from main (sync response)';
});// 7. handle:注册异步请求处理函数,用于 ipcRenderer.invoke
ipcMain.handle('example-invoke', async (event, arg) => {console.log('[Main] handle: Handling invoke request with arg:', arg);// 模拟异步处理,返回结果return `Response from main for "${arg}"`;
});// 8. handleOnce:注册一次性异步处理函数
ipcMain.handleOnce('example-handleOnce', async (event, arg) => {console.log('[Main] handleOnce: Handling one-time request with arg:', arg);return `One-time response from main for "${arg}"`;
});// 9. removeHandler:移除先前注册的 handler
ipcMain.handle('example-removeHandler', async (event, arg) => {console.log('[Main] handle (to be removed):', arg);return `Response for "${arg}"`;
});
// 当需要移除该处理器时:
ipcMain.removeHandler('example-removeHandler');
3. ipcRenderer
渲染进程
// 1. on:注册持续监听器,接收主进程发送的事件
window.electronAPI.on('example-on', (event, data) => {console.log('[Renderer] on: Received "example-on" message:', data);
});// 2. once:注册一次性监听器,只触发一次后自动移除
window.electronAPI.once('example-once', (event, data) => {console.log('[Renderer] once: Received "example-once" message:', data);
});// 3. addListener:与 on 相同(别名),注册监听器
window.electronAPI.addListener('example-addListener', (event, data) => {console.log('[Renderer] addListener: Received "example-addListener" message:', data);
});// 4. off:移除之前注册的监听器
function exampleOffListener(event, data) {console.log('[Renderer] off: This listener will be removed, data:', data);
}
window.electronAPI.on('example-off', exampleOffListener);
// 当不需要时:
window.electronAPI.off('example-off', exampleOffListener);// 5. removeListener:与 off 功能相同,移除指定监听器
function exampleRemoveListener(event, data) {console.log('[Renderer] removeListener: Listener to be removed, data:', data);
}
window.electronAPI.addListener('example-removeListener', exampleRemoveListener);
// 移除它:
window.electronAPI.removeListener('example-removeListener', exampleRemoveListener);// 6. removeAllListeners:移除指定通道上所有监听器
window.electronAPI.removeAllListeners('example-removeAll');// 7. send:异步发送消息到主进程(火箭式发送,不等待返回)
window.electronAPI.send('example-send', 'Hello from renderer via send');// 8. invoke:异步调用主进程方法,返回 Promise,可使用 await 获取结果
window.electronAPI.invoke('example-invoke', 'Hello from renderer via invoke').then(response => {console.log('[Renderer] invoke: Received response:', response);}).catch(err => {console.error('[Renderer] invoke: Error:', err);});// 9. sendSync:同步发送消息,并等待主进程返回结果(会阻塞当前进程,谨慎使用)
const syncResult = window.electronAPI.sendSync('example-sendSync', 'Hello from renderer via sendSync');
console.log('[Renderer] sendSync: Received response:', syncResult);// 10. postMessage:通过 MessagePort 机制发送消息,适用于嵌入式 Webview 或隔离上下文的场景
// 此方法通常用于与嵌入的内容通信,这里仅作示例:
window.electronAPI.postMessage('example-postMessage', { msg: 'Hello via postMessage' }, []);// 11. sendToHost:用于 Webview 内部向宿主发送消息(仅在 webview 中有效)
// 检查是否存在(在非 webview 环境下可能为 undefined)
if (window.electronAPI.sendToHost) {window.electronAPI.sendToHost('example-sendToHost', 'Hello from webview to host');
}
五、总结
发送消息
- 单向通知:使用 ipcRenderer.send(主进程通过 ipcMain.on 监听);适合简单指令,不需要立即反馈。
- 同步调用:使用 sendSync(阻塞渲染进程,不推荐用于耗时任务)。
- RPC 请求:使用 invoke(返回 Promise),由主进程 handle 或 handleOnce 处理,适合需要异步返回结果的场景。
- 特殊场景:postMessage 和 sendToHost 针对嵌入式内容与宿主的跨上下文通信设计。
监听消息
- 主进程和渲染进程均提供了 on、once 及其别名方法,用于注册事件监听;同时提供相应的移除方法(如 off、removeListener、removeAllListeners)用于管理监听器,保证资源及时释放。
整体对比
- 异步、非阻塞:send、invoke、on、handle 等方法均采用异步方式,推荐在大部分场景中使用。
- 同步阻塞:sendSync 适合简单、快速的任务,但可能阻塞 UI,不建议用于复杂操作。
- 请求/响应模式:invoke 与 handle 为现代 IPC 通信的首选,代码风格清晰且便于错误处理。
- 特殊通信:postMessage 与 sendToHost 针对特殊嵌入场景,适合 Webview 或多上下文安全通信。