你得了解:
进程(process):
一个进程是计算机程序执行中的一个实例。 Electron 应用同时使用了 main
进程和一个或者多个 renderer
进程来运行多个程序。
在 Node.js 和 Electron 里面,每个运行的进程包含一个 process
对象。 这个对象作为一个全局的提供当前进程的相关信息和操作方法。 作为一个全局变量,它在应用内能够不用 require() 来随时取到。
主进程(main process):
主进程,通常是指 main.js
文件,是每个 Electron 应用的入口文件。 控制着整个应用的生命周期,从打开到关闭。 它也管理着系统原生元素比如菜单,菜单栏,Dock 栏,托盘等。 主进程负责创建 APP 的每一个渲染进程。 包含了全功能的 Node API。
应用的主进程定义在 package.json
中的 main
属性中。 当您运行 electron .
时 Electron 便会知道需要运行哪个文件。
在Chromium中,此进程被称为“浏览器进程”。 Electron 中这样称呼是为了不与渲染进程混淆。
渲染进程(renderer process):
渲染进程是应用中的浏览器窗口。 与主进程不同,渲染进程可能同时存在多个,同时,每一个渲染进程都运行与独立的进程中。 渲染进程也可以隐藏。
正文:
IPC
IPC
代表进程间通信。 Electron使用IPC在主进程和渲染器进程之间发送 序列化的JSON消息。
ipcMain
进程:主进程
从主进程到渲染进程的异步通信
ipcMain
是一个 EventEmitter 的实例。 当在主进程中使用时,它处理从渲染器进程(网页)发送出来的异步和同步信息。 从渲染器进程发送的消息将被发送到该模块。
ipcRenderer
进程: Renderer
从渲染器进程到主进程的异步通信
ipcRenderer
是一个 EventEmitter 的实例。 你可以使用它提供的一些方法从渲染进程 (web 页面) 发送同步或异步的消息到主进程。 也可以接收主进程回复的消息。
渲染进程间的直接通讯不被允许的,虽然ipcRenderer
是一个 EventEmitter 的实例,可以自己emit
自己on
webContents
进程:主进程
webContents
是一个 EventEmitter。 负责渲染和控制网页, 是 BrowserWindow
对象的一个属性。
主进程与主进程
1.ipcMain.emit 和 ipcMain.on
因为ipcMain
是一个 EventEmitter 的实例,可以自己emit
给自己on
const { ipcMain } = require("electron");
//发事件
ipcMain.emit(customEventName, params);
//监听事件
ipcMain.on(customEventName, (event, params) => {});
2.mainWin.webContents.emit 和 mainWin.webContents.on
因为 webContents
是一个 EventEmitter 的实例,可以自己emit
给自己on
注意: 使用 webContents.send
在此场景下,webContents.on
监听不到,webContents.send
不等同于 webContents.emit
const { ipcMain, BrowserWindow } = require("electron");
app.on("ready", () => {
const mainWin = new BrowserWindow();
//发事件
mainWin.webContents.emit(customEventName, params);
//监听事件
mainWin.webContents.on(customEventName, (event, params) => {});
});
主进程与渲染进程
假设 mainWin
是 BrowserWindow
的一个实例,mainWin.send == mainWin.webContents.send
主进程 -> 渲染进程
const { ipcMain, BrowserWindow } = require("electron");
app.on("ready", () => {
const mainWin = new BrowserWindow();
//发事件
mainWin.webContents.send(customEventName, params);
//或者mainWin.send
});
// 渲染进程,如render.js
const { ipcRenderer } = require("electron");
ipcRenderer.on(eventName, handler);
渲染进程 -> 主进程
渲染进程依赖 ipcRenderer 模块给主进程发送消息,官方提供了三个方法:
ipcRenderer.send(channel, …args)
ipcRenderer.invoke(channel, …args)
ipcRenderer.sendSync(channel, …args)
channel
表示的就是事件名(消息名称), args
是参数。需要注意的是参数将使用结构化克隆算法进行序列化,就像浏览器的 window.postMessage 一样,因此不会包含原型链。发送函数、Promise、Symbol、WeakMap 或 WeakSet 将会抛出异常。
1.即发即弃(单向)
要将单向 IPC 消息从渲染器进程发送到主进程,您可以使用 ipcRenderer.send
API 发送消息,然后使用 ipcMain.on
API 接收。
//发
ipcRenderer.send(customEventName, params);
//监听
ipcMain.on(customEventName, (event, params) => {});
如果使用 send
来发送数据,且需要回复主进程消息,那么需要使用 event.replay
来进行回复,同时,渲染进程需要进行额外的监听:
ipcMain.on(customEventName, (event, message) => {
// result 为处理结果
event.reply("reply", result);
});
// 额外需要 reply 接受
ipcRenderer.on("reply", (event, message) => {});
2.请求-响应(双向)
双向 IPC 的一个常见应用是从渲染器进程代码调用主进程模块并等待结果。
1.可以通过将 ipcRenderer.invoke
与 ipcMain.handle
搭配使用来完成。
//发
ipcRenderer.invoke(customEventName, params).then(res => {
// 接收一个返回值
});
//监听
ipcMain.handle(customEventName, (event, params) => {
// return 一个返回值
});
注意,渲染进程通过
ipcRenderer.invoke
发送消息后,invoke
的返回值是一个Promise
。主进程回复消息需要通过return
的方式进行回复,而ipcRenderer
只需要等到Promise resolve
即可获取到返回的值。
2.也可以通过将 ipcRenderer.sendSync
与 ipcMain.on
搭配使用来完成。
//发
async function sendSyncMessageToMain() {
const replyMessage = await ipcRenderer.sendSync(customEventName, params);
}
//监听
ipcMain.on(customEventName, (event, message) => {
event.returnValue = "replay";
});
注意,渲染进程通过
ipcRenderer.sendSync
发送消息后,主进程回复消息需要通过e.returnValue
的方式进行回复,如果event.returnValue
不为undefined
的话,渲染进程会等待sendSync
的返回值才执行后面的代码。
3.ipcRenderer.invoke
与ipcRenderer.sendSync
的区别
ipcRenderer.sendSync
是同步的,用于从渲染进程向主进程发送消息,但是它会等待主进程返回响应,会阻塞当前进程,直到收到主进程的返回值或者超时。
ipcRenderer.invoke
是异步的,也是用于从渲染进程向主进程发送消息,但在渲染进程中可以等待主进程返回 Promise 结果进行异步操作。
渲染进程与渲染进程
渲染进程1 -> 渲染进程2 的实现:
- 渲染进程1 -> 主进程(中转代理) -> 渲染进程2
- 从主进程将一个 MessagePort 传递到两个渲染器。 这将允许在初始设置后渲染器之间直接进行通信。