使用消息端口通信
使用消息端口通信
MessageChannel
文档地址:https://developer.mozilla.org/en-US/docs/Web/API/MessageChannel
MessageChannel 是一个浏览器所支持的 Web API,它允许我们创建一个消息通道,并通过它的两个 MessagePort 属性发送数据。每个 MessageChannel 实例都有两个端口:port1 和 port2,这使得它们可以相互通信,就像是一个**双向通信**的管道。
双向通信和单向通信是通信系统中的两种基本通信模式。
- 双向通信
双向通信,顾名思义,是**信息可以在两个方向上流动的通信方式。这意味着参与通信的双方既可以发送信息,也可以接收信息**。
生活中也有很多双向通信的例子:
- 两个人在进行面对面的对话。每个人都可以说话(发送信息)也可以听对方说话(接收信息)。这种通信方式允许实时的互动和反馈
- 使用即时通讯软件聊天,双方都可以发送和接收消息。
常见的双向通信的实现:
- 电话通话:两个人可以同时进行听和说的活动。
- 网络聊天应用(如WhatsApp, WeChat):用户可以发送消息并接收对方的回复。
- WebSocket 协议:在 Web 开发中,WebSocket 提供了一个全双工通信渠道,允许数据在客户端和服务器之间双向流动。
- 单向通信
单向通信是指**信息只能在一个方向上流动的通信方式。这意味着通信的一方仅能发送信息,而另一方仅能接收信息**,反向的信息流动是不可能的。
生活中也存在单向通信的例子:
收听广播或看电视。广播站或电视台(发送方)向外播出节目,而听众或观众(接收方)只能接收内容,不能通过这个渠道回应。在这种情况下,信息的流动是单向的。
常见的单项通信的实现:
- 广播系统:如无线电广播,只能传输信息,收听者不能通过广播回传信息。
- 通知系统:比如网站的推送通知功能,服务器可以向客户端发送通知,但客户端不能通过这些通知回复服务器。
- RSS Feeds:允许用户订阅来自网站的更新,但用户不能通过 RSS 向网站发送信息。
这个功能特别适合于需要从**一个上下文(比如主页面)与另一个上下文(例如 Web Worker 或者 iframe)安全地通信的情况**。也就是说,进行跨上下文进行通信。
Electron中的消息端口
在 Electron 中,涉及到一个主进程、一个渲染进程。如果是在渲染进程中,那么我们是可以正常使用 MessageChnnel 的。
但是如果换做是在主进程中,是**不存在 MessageChannel 类的**,因为这其实是一个 Web API,主进程不是网页,它没有 Blink 的集成,因此自然是不能使用的。
不过,Electorn 中针对该情况,为主进程新增了一个 MessageChannelMain 类,该类的行为就类似于 MessageChannel。
代码
主进程
// 1. 启动一个 Worker,单独启动一个 Worker,可以做一些比较耗时的操作
// 2. 然后我们使用 MessageChannel 与 Worker 进行通信
document.getElementById("sendMessage").addEventListener("click", () => {
// 1. 初始化一个 Worker
const worker = new Worker("worker.js");
// 2. 创建一个 messagechannel
// 创建了一个 MessageChannel 对象,然后我们可以通过它的 port1 和 port2 属性来进行通信
// 我们这个 main.js 上下文要留一个 prot,然后把另一个 port 传递给 Worker
const channel = new MessageChannel();
// 监听来自 Worker 发过来的消息
channel.port1.onmessage = (event) => {
document.getElementById("data-display").textContent =
`从 Worker 接收到的数据:${event.data}`;
};
// 这里就将 port2 传递给 Worker
worker.postMessage("Hello World", [channel.port2]);
});
worker.js
self.onmessage = (event) => {
// 拿到主线程给我传递过来的 port2
const port = event.ports[0];
if (port) {
// 我们就使用这个 port 不停的给主线程发送消息
setInterval(() => {
// 生成一个随机的数据传递给主线程
port.postMessage(Math.random());
}, 1000);
}
};