JavaScript 如何实现同源通信
作者:全栈修仙之路 发布时间:2024-07-15 21:16:02
一、Broadcast Channel API 简介
Broadcast Channel API 可以实现同源下浏览器不同窗口、Tab 页或者 iframe 下的浏览器上下文之间的简单通讯。通过创建一个监听某个频道下的 BroadcastChannel 对象,你可以接收发送给该频道的所有消息。
(图片来源 —— https://developer.mozilla.org/zh-CN/docs/Web/API/Broadcast_Channel_API)
了解完 Broadcast Channel API 的作用之后,我们来看一下如何使用它:
// 创建一个用于广播的通信通道
const channel = new BroadcastChannel('my_bus');
// 在my_bus上发送消息
channel.postMessage('大家好,我是阿宝哥');
// 监听my_bus通道上的消息
channel.onmessage = function(e) {
console.log('已收到的消息:', e.data);
};
// 关闭通道
channel.close();
通过观察以上示例,我们可以发现 Broadcast Channel API 使用起来还是很简单的。该 API 除了支持发送字符串之外,我们还可以发送其它对象,比如 Blob、File、ArrayBuffer、Array 等对象。另外,需要注意的是,在实际项目中,我们还要考虑它的兼容性:
(图片来源 —— https://caniuse.com/?search=Broadcast%20Channel%20API)
由上图可知,在 IE 11 及以下的版本,是不支持 Broadcast Channel API,这时你就可以考虑使用现成的 broadcast-channel-polyfill 或者基于 localStorage 和 storage 事件来实现。
二、Broadcast Channel API 应用场景
利用 Broadcast Channel API,我们可以轻易地实现同源页面间一对多的通信。该 API 的一些使用场景如下:
实现同源页面间数据同步;
在其它 Tab 页面中监测用户操作;
指导 worker 执行一个后台任务;
知道用户何时登录另一个 window/tab 中的帐户。
为了让大家能够更好地掌握 Broadcast Channel API,阿宝哥以前面 2 个使用场景为例,来介绍一下该 API 的具体应用。
2.1 实现同源页面间数据同步
html
<h3 id="title">你好,</h3>
<input id="userName" placeholder="请输入你的用户名" />
JS
const bc = new BroadcastChannel("abao_channel");
(() => {
const title = document.querySelector("#title");
const userName = document.querySelector("#userName");
const setTitle = (userName) => {
title.innerHTML = "你好," + userName;
};
bc.onmessage = (messageEvent) => {
if (messageEvent.data === "update_title") {
setTitle(localStorage.getItem("title"));
}
};
if (localStorage.getItem("title")) {
setTitle(localStorage.getItem("title"));
} else {
setTitle("请告诉我们你的用户名");
}
userName.onchange = (e) => {
const inputValue = e.target.value;
localStorage.setItem("title", inputValue);
setTitle(inputValue);
bc.postMessage("update_title");
};
})();
在以上示例中,我们实现了同源页面间的数据同步。当任何一个已打开的页面中,输入框的数据发生变化时,页面中的 h3#title 元素的内容将会自动实现同步更新。
2.2 在其它 Tab 页面中监测用户操作
利用 Broadcast Channel API,除了可以实现同源页面间的数据同步之外,我们还可以利用它来实现在其它 Tab 页面中监测用户操作的功能。比如,当用户在任何一个 Tab 中执行退出操作后,其它已打开的 Tab 页面也能够自动实现退出,从而保证系统的安全性。
html
<h3 id="status">当前状态:已登录</h3>
<button onclick="logout()">退出</button>
JS
const status = document.querySelector("#status");
const logoutChannel = new BroadcastChannel("logout_channel");
logoutChannel.onmessage = function (e) {
if (e.data.cmd === "logout") {
doLogout();
}
};
function logout() {
doLogout();
logoutChannel.postMessage({ cmd: "logout", user: "阿宝哥" });
}
function doLogout() {
status.innerText = "当前状态:已退出";
}
在以上示例中,当用户点击退出按钮后,当前页面会执行退出操作,同时会通过 logoutChannel 通知其它已打开的页面执行退出操作。
三、Broadcast Channel API vs postMessage API
与 postMessage() 不同的是,你不再需要维护对 iframe 或 worker 的引用才能与其进行通信:
const popup = window.open('https://another-origin.com', ...);
popup.postMessage('Sup popup!', 'https://another-origin.com');
Broadcast Channel API 只能用于实现同源下浏览器不同窗口、Tab 页或者 iframe 下的浏览器上下文之间的简单通讯。而 postMessage API 却可用于实现不同源之间消息通信。由于保证消息来自同一来源,因此无需像以前那样使用以下方法来验证消息:
const iframe = document.querySelector('iframe');
iframe.contentWindow.onmessage = function(e) {
if (e.origin !== 'https://expected-origin.com') {
return;
}
e.source.postMessage('Ack!', e.origin);
};
四、总结
Broadcast Channel API 是一个非常简单的 API,内部包含了跨上下文通讯的接口。在支持该 API 的浏览器中,我们可以利用该 API 轻松地实现同源页面间的通信。而对于不支持该 API 的浏览器来说,我们就可以考虑使用 localStorage 和 storage 事件来解决同源页面间通信的问题。
五、参考资源
MDN - Broadcast Channel API
BroadcastChannel API: A Message Bus for the Web
来源:https://mp.weixin.qq.com/s/hw_IUf7cs7YpCKvphz18Zg


猜你喜欢
- 系统环境:64位win7企业版python2.7.102016.08.16修改内容:1)read_until()函数是可以设置timeout
- timeit.repeattimeit.repeat默认会执行3轮,每轮执行1000000次。返回每轮的总执行时间列表字典获取性能大家都知道
- 有些项目可能涉及到使用多个数据库的情况,方法很简单。1.在settings中设定DATABASE比如要使用两个数据库:DATABASES =
- 先设置一个关于书本(book)的数据模型:from django.db import modelsclass Publisher(model
- 进过两天的研究终于实现了cookie的免密登录,其实就是session。特别开心,因为在Python爬虫群里问那些大佬,可是他们的回答令我寒
- 在现实的图像操作软件中,经常碰到的不是给出放大多少倍,而是由用户在软件的界面上选择多大的区域,或者选择几个点,那么这样情况下,怎么样来计算出
- 1.外形尺寸尺寸单位:只用默认的像素或者其他字符类的值!,不要用英寸毫米之类的内容。btn = tkinter.Button(root,te
- 懒加载:也叫延迟加载,即在需要的时候进行加载,随用随载。 像vue这种单页面应用,如果没有应用懒加载,运用webpack打包后的文
- python纵向合并任意多个图片,files是要拼接的文件list# -*- coding:utf-8 -*-def mergeReport
- 切片的解析当我们的代码敲下[]时,便会被go编译器解析为抽象语法树上的切片节点, 被初始化为切片表达式SliceType:// go/src
- <% Function ReplaceUrl2(HTMLstr) Dim n,st
- Windows下采用PyInstall将py文件转换成exe可执行文件好不容易写完的py文件,想做成exe文件,最开始选择用py2exe,结
- 在我们的生活中,只要你睁开眼睛就能看到各种各样的视觉。不同的视觉能给你不同的视觉暗示,同样能给你不同的心理感受。视觉这个话题太泛了,大自然中
- 目录1. matplotlib 模块概述2. matplotlib.pyplot 相关方法3. matplotlib.pyplot 图表展示
- 1.引言本文是Python生态系统中一些有用技巧的分享。大多数技巧只是使用标准库中的包,但其他一些技巧会涉及一些第三方包。在开始阅读本文内容
- 本文介绍的是关于Python利用字典的默认行为的相关内容,分享出来供大家参考学习,下面来看看详细的介绍:典型代码1:from collect
- python包含子目录中的模块方法比较简单,关键是能够在sys.path里面找到通向模块文件的路径。下面将具体介绍几种常用情况:(1)主程序
- 1.gorm介绍1.1介绍全功能 ORM关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表
- 当我们需要将一个一维数组转换成一个多层结构的时候,最简单但是最慢的就是多个for循环嵌套,但是这样做有一些缺点,那就是效率太低、而且有多少层
- 喜欢用Python写脚本的小伙伴可以跟着一起写一写呀。编写环境:Python2.x00x1:需要用到的模块需要用到的模块如下:import