electron进程间通讯


你得了解:

进程(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) => {});
});

主进程与渲染进程

假设 mainWinBrowserWindow 的一个实例,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.invokeipcMain.handle 搭配使用来完成。

//发
ipcRenderer.invoke(customEventName, params).then(res => {
    // 接收一个返回值
});

//监听
ipcMain.handle(customEventName, (event, params) => {
    // return 一个返回值
});

注意,渲染进程通过 ipcRenderer.invoke 发送消息后,invoke 的返回值是一个 Promise 。主进程回复消息需要通过 return 的方式进行回复,而 ipcRenderer 只需要等到 Promise resolve 即可获取到返回的值。

2.也可以通过将 ipcRenderer.sendSyncipcMain.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.invokeipcRenderer.sendSync的区别

ipcRenderer.sendSync是同步的,用于从渲染进程向主进程发送消息,但是它会等待主进程返回响应,会阻塞当前进程,直到收到主进程的返回值或者超时。

ipcRenderer.invoke是异步的,也是用于从渲染进程向主进程发送消息,但在渲染进程中可以等待主进程返回 Promise 结果进行异步操作。

渲染进程与渲染进程

渲染进程1 -> 渲染进程2 的实现:

  • 渲染进程1 -> 主进程(中转代理) -> 渲染进程2
  • 从主进程将一个 MessagePort 传递到两个渲染器。 这将允许在初始设置后渲染器之间直接进行通信。

文章作者: 弈心
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 弈心 !
评论
  目录