你得了解:
进程(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 传递到两个渲染器。 这将允许在初始设置后渲染器之间直接进行通信。