深入理解Electron 中的 MessagePorts

1,839 阅读2分钟

简介

在 Electron 应用程序中,MessagePorts 是一种允许在不同上下文之间传递消息的机制。它类似于 window.postMessage 机制,但是在不同的通道上工作。本教程将详细介绍 MessagePorts 的概念、使用方法和示例代码。

MessagePorts 概念

MessagePorts 是成对创建的,消息发送到一个端口将被另一个端口接收。它们可以用于在不同上下文之间通信,例如主进程和渲染进程之间,或者不同渲染进程之间。

在主进程中的 MessagePorts

由于主进程不是一个网页,因此它不具有原生的 MessagePortMessageChannel 类。Electron 添加了 MessagePortMainMessageChannelMain 类来处理主进程中的 MessagePorts。

close 事件

Electron 还添加了一个 close 事件到 MessagePort 对象上,该事件在通道的另一端关闭时触发。

示例用例

1. 在两个渲染进程之间设置 MessageChannel

在这个示例中,我们将创建一个 MessageChannel,并将其传递给两个渲染进程。然后,我们将在两个渲染进程之间发送消息。

// 主进程
const { MessageChannel } = require('electron');

let channel = new MessageChannel();
let port1 = channel.port1;
let port2 = channel.port2;

// 将 port1 传递给渲染进程 1
win1.webContents.send('set-port', port1);

// 将 port2 传递给渲染进程 2
win2.webContents.send('set-port', port2);

// 渲染进程 1
ipcRenderer.on('set-port', (event, port) => {
  port.postMessage('Hello from renderer 1!');
});

// 渲染进程 2
ipcRenderer.on('set-port', (event, port) => {
  port.onmessage = (event) => {
    console.log(`Received message from renderer 1: ${event.data}`);
  };
});

2. 使用 MessageChannel 与隐藏的 "worker" 进程通信

在这个示例中,我们将创建一个隐藏的 "worker" 进程,并使用 MessageChannel 与其通信。

// 主进程
const { BrowserWindow } = require('electron');

let workerWin = new BrowserWindow({
  show: false,
  webPreferences: {
    nodeIntegration: true
  }
});

let channel = new MessageChannel();
let port1 = channel.port1;
let port2 = channel.port2;

workerWin.webContents.send('set-port', port2);

// 主进程
port1.postMessage('Hello from main process!');

// 工作进程
ipcRenderer.on('set-port', (event, port) => {
  port.onmessage = (event) => {
    console.log(`Received message from main process: ${event.data}`);
  };
});

3. 使用 MessageChannel 实现 "response stream"

在这个示例中,我们将使用 MessageChannel 实现一个 "response stream",其中单个请求可以响应一个数据流。

// 主进程
const { MessageChannel } = require('electron');

let channel = new MessageChannel();
let port1 = channel.port1;
let port2 = channel.port2;

// 将 port1 传递给渲染进程
win.webContents.send('set-port', port1);

// 渲染进程
ipcRenderer.on('set-port', (event, port) => {
  port.postMessage('Request data!');

  port.onmessage = (event) => {
    console.log(`Received data: ${event.data}`);
  };
});

// 主进程
port2.onmessage = (event) => {
  let data = ['data1', 'data2', 'data3'];
  data.forEach((item) => {
    port2.postMessage(item);
  });
};

4. 直接在主进程和渲染进程之间通信

在这个示例中,我们将直接在主进程和渲染进程之间使用 MessageChannel 进行通信。

// 主进程
const { MessageChannel } = require('electron');

let channel = new MessageChannel();
let port1 = channel.port1;
let port2 = channel.port2;

// 将 port1 传递给渲染进程
win.webContents.send('set-port', port1);

// 渲染进程
ipcRenderer.on('set-port', (event, port) => {
  port.postMessage('Hello from renderer!');

  port.onmessage = (event) => {
    console.log(`Received message from main process: ${event.data}`);
  };
});

// 主进程
port2.onmessage = (event) => {
  console.log(`Received message from renderer: ${event.data}`);
  port2.postMessage('Hello from main process!');
};

结论

MessagePorts 是 Electron 应用程序中的一种强大机制,允许在不同上下文之间传递消息。通过本教程,您应该已经了解了 MessagePorts 的概念、使用方法和示例代码。