Electron进程间通信
在说Electron进程通信的时候,先说一下Electron中的两种进程:主进程和渲染进程。
主进程通过创建 BrowserWindow
实例来创建网页。 每一个 BrowserWindow
实例在其渲染过程中运行网页,当一个BrowserWindow
实例被销毁时,对应的渲染过程也会被终止。简单来说,一个客户端就是一个主进程。
渲染进程只能管理相应的网页,一个渲染进程的崩溃不会影响其他渲染进程。渲染进程通过 IPC
与主进程通信在网在页上执行 GUI
操作。 出于安全和可能的资源泄漏考虑,直接从渲染器进程中调用与本地 GUI
有关的 API
受到限制。简单来说,一个页面就是一个渲染进程。
注意:主进程管理所有网页及其对应的渲染进程。
1. 使用IPC模块进行通信
ipcMain
模块和 ipcRenderer
是类 EventEmitter
的实例。在渲染进程中使用ipcRender
模块向主进程发送消息,主进程中ipcMain
接收消息,进行操作,如果还需要反馈,则通知渲染进程,渲染进程根据接收的内容执行相应的操作。
ipcMain相关文档:https://www.electronjs.org/docs/api/ipc-main
ipcRenderer相关文档:https://www.electronjs.org/docs/api/ipc-renderer
1.1 异步消息
主进程将异步消息发送回发件人,需要使用event.sender.send()
// 渲染进程中
const {ipcRenderer} = require('electron')
ipcRenderer.send('asynchronous-message', 'ping') //给Main进程发送消息 'ping'
ipcRender.on('asynchronous-reply', function (event, arg) { // 接收到Main进程返回的消息
const message = `异步消息回复: ${arg}`
})
// 主进程中
const {ipcMain} = require('electron')
ipcMain.on('asynchronous-message',(event, arg) => { // arg为接受到的消息
event.sender.send('asynchronous-reply', 'pong'); // 返回一个 'pong'
})
1.2 同步消息
此方法的同步特性意味着它在完成任务时会阻止其他操作,主进程回复同步信息时,需要设置event.returnValue
// 渲染进程中
const {ipcRenderer} = require('electron')
ipcRenderer.sendSync('synchronous-message', 'ping') //给Main进程发送消息 'ping'
ipcRender.on('synchronous-reply', function (event, arg) { // 接收到Main进程返回的消息
const message = `同步消息回复: ${arg}`
})
// 主进程中
const {ipcMain} = require('electron')
ipcMain.on('synchronous-message',(event, arg) => { // arg为接受到的消息
event.returnValue = 'pong' // 返回一个 'pong'
})
注意:切忌用 ipc
传递大量的数据,会有很大的性能问题,严重会让你整个应用卡住。
2. webContents.send方法实现通信
webcontents相关文档:https://www.electronjs.org/docs/api/web-contents
webContents.send
是BrowserWindow类的一个方法。
// 主进程中
mainWindow.webContents.send('list', res.data); // mainWindow是一个BrowserWindow实例
// 渲染进程中
const {ipcRenderer} = require('electron')
ipcRenderer.on('list', (e, msg) => {
console.log(msg);
});
3. 渲染进程之间的通信
如果数据不需要实时性,只是渲染进程之间数据的共享,可以使用localStorage
、sessionStorage
和IndexedDB
,如果需要实时共享,可以利用主进程做消息中转或者利用 remote
接口直接获取渲染进程发送消息。
3.1 利用主进程把渲染进程1的消息发送给渲染进程2中
// 主进程中监听ping-event
ipcMain.on('ping-event', (event, arg) => {
mainWindow.webContents.send('pong-event', 'something'); // mainWindow是一个BrowserWindow实例
// 或者
event.sender.send('pong-event', 'something');
}
// 渲染进程1
const {ipcRenderer} = require('electron')
ipcRenderer.send('ping-event', (event, arg) => {
// do something
}
)
// 渲染进程2
const {ipcRenderer} = require('electron')
ipcRenderer.on('pong-event', (event, arg) => {
// do something
}
)
3.2 使用remote或者ipcRenderer.sendTo
// 主进程
// 两个窗口互相获取对方的窗口 id, 并发送给渲染进程
win1.webContents.send('distributeIds',{
win2Id : win2.id
});
win2.webContents.send('distributeIds',{
win1Id : win1.id
});
// 渲染进程
// 渲染进程1通过 id 发送给渲染进程2
const {ipcRenderer} = require('electron')
remote.BrowserWindow.fromId(win2Id).webContents.send('someMsg', 'someThing');
// 或者
ipcRenderer.sendTo(win2Id, 'someMsg', 'someThing')