😄 19年之后由于某些原因断更了三年,23年重新扬帆起航,推出更多优质博文,希望大家多多支持~
🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志
🎐 个人CSND主页——Micro麦可乐的博客
🐥《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程,入门到实战
🌺《RabbitMQ》专栏主要介绍使用JAVA开发RabbitMQ的系列教程,从基础知识到项目实战
🌸《设计模式》专栏以实际的生活场景为案例进行讲解,让大家对设计模式有一个更清晰的理解
💕《Jenkins实战》专栏主要介绍Jenkins+Docker的实战教程,让你快速掌握项目CI/CD,是2024年最新的实战教程
🌞《Spring Boot》专栏主要介绍我们日常工作项目中经常应用到的功能以及技巧,代码样例完整
如果文章能够给大家带来一定的帮助!欢迎关注、评论互动~
【前端技术】标签页通讯localStorage、BroadcastChannel、SharedWorker的技术详解
- 前言
- 标签页通信的应用场景
- ❶ 用户登录状态同步
- ❷ 实时数据更新
- ❸ 多标签页协同工作
- ❹ 购物车同步
- ❺视频、音频播放同步
- 第一种:localStorage
- 第二种:BroadcastChannel API
- 第三种:SharedWorker
- 结语
前言
随着 Web 应用的复杂化和功能的增加,很多时候我们某些业务功能需要实现标签页间的通讯,基于这种需求下,我们必须要掌握一些标签页通讯的技术,本文博主将和大家分享三种常见的标签页通讯技术: localStorage
事件、 BroadcastChannel API
和 SharedWorker
标签页通信的应用场景
浏览器标签页之间的通讯在实际应用中有很多场景。下面博主举几个常见的例子,展不同的需求和解决方案
❶ 用户登录状态同步
应用场景:用户在一个标签页中登录或注销,其他打开同一应用的标签页需要同步登录状态。
解决方案:使用 localStorage
事件或 BroadcastChannel
❷ 实时数据更新
应用场景:在一个标签页中更新数据,其他标签页需要实时显示更新结果,例如股票行情、实时聊天消息等。
解决方案:使用 BroadcastChannel
实现高效的实时通讯。
❸ 多标签页协同工作
应用场景:用户在多个标签页中打开同一个应用,需要各标签页协同工作。例如,在一个标签页中填写表单,另一个标签页显示表单预览
解决方案:使用 SharedWorker
进行复杂数据和状态共享,或者 BroadcastChannel
进行简单消息传递
❹ 购物车同步
应用场景:用户在一个标签页中添加商品到购物车,其他标签页需要同步购物车内容
解决方案:使用 localStorage 事件或 BroadcastChannel 实现购物车内容的同步
❺视频、音频播放同步
应用场景:用户在多个标签页中同时打开同一个视频,控制一个标签页的视频播放,其他标签页的视频需要同步播放或暂停(可以参考国内的酷狗音乐网站: 播放音乐标签页的效果)
解决方案:使用 BroadcastChannel 实现同步控制
以上举例仅仅是标签页通讯应用场景的其中几种,实际上还存在更多场景,博主就不一一展开了
第一种:localStorage
localStorage
是一种持久化的存储机制,它允许在浏览器中存储键值对。当 localStorage
的数据在一个标签页中被修改时,其他所有打开同一页面的标签页都会接收到一个 storage
事件。这一特性使得我们可以利用 localStorage
实现不同标签页之间的通讯。
localStorage 的基本特点
- 持久性:数据存储在 localStorage 中,即使浏览器关闭后也会保留
- 同源策略:同一来源(origin)下的所有页面都可以访问相同的 localStorage 数据
- 容量限制:大多数浏览器限制在 5MB 左右
代码示例
下面我们通过一个具体的示例,展示如何利用 localStorage
实现标签页之间的通讯
标签页 A:发送消息
<!DOCTYPE html>
<html>
<head>
<title>标签页 A</title>
</head>
<body>
<button onclick="sendMessage('这是来自标签页A的消息')">发送消息</button>
<script>
function sendMessage(message) {
localStorage.setItem('message', message);
}
</script>
</body>
</html>
标签页 B:接收消息
<!DOCTYPE html>
<html>
<head>
<title>标签页 B</title>
</head>
<body>
<script>
window.addEventListener('storage', (event) => {
if (event.key === 'message') {
console.log('我是标签页B接受到的消息: ', event.newValue);
}
});
</script>
</body>
</html>
localStorage标签页通讯优点
- 简单易用:实现方法简单,代码量少
- 浏览器支持广泛:大多数现代浏览器都支持 localStorage
localStorage标签页通讯缺点
- 同步问题:storage 事件是异步的,不适用于需要实时通讯的场景。
- 数据存储限制:localStorage 容量有限,一般为 5MB。
- 安全性:localStorage 中的数据是明文存储的,需要注意敏感数据的存储安全。
第二种:BroadcastChannel API
BroadcastChannel
是一种用于在同一来源(同一协议、主机名和端口号)下不同浏览器上下文(如标签页
、iframe
、Worker
、Service Worker
)之间进行消息广播的 API。它提供了一种简便、可靠的方法来实现跨上下文的实时通讯
BroadcastChannel 的基本概念
- 广播频道:BroadcastChannel 创建的实例代表一个特定的广播频道,所有监听该频道的上下文都能接收该频道发送的消息
- 消息广播:通过 postMessage 方法发送消息,所有监听该频道的上下文都会收到消息
- 消息监听:通过 onmessage 事件处理器接收和处理来自该频道的消息
BroadcastChannel 的特点
- 实时通讯:能够在不同浏览器上下文之间进行实时消息传递。
- 简洁易用:API 简单明了,只需少量代码即可实现。
- 同源策略:确保安全性,只有同源的上下文才能相互通讯。
基本用法
创建频道:在多个上下文中使用相同的频道名称创建 BroadcastChannel
实例
const channel = new BroadcastChannel('my_channel');
发送消息:在任意一个上下文中,通过 postMessage
方法向频道发送消息
channel.postMessage('Hello from one context');
接收消息:在其他上下文中,通过监听 onmessage
事件接收消息
channel.onmessage = (event) => {
console.log('Received message:', event.data);
};
代码示例
通过上述基本用法的介绍,我们现在可以用一个代码示例来演示一下
标签页 A 的代码
<!DOCTYPE html>
<html>
<head>
<title>Page A</title>
</head>
<body>
<button onclick="sendMessage()">发送消息</button>
<script>
const channel = new BroadcastChannel('my_channel');
function sendMessage() {
channel.postMessage('这是来自标签页A的消息');
//传递对象
channel.postMessage({ type: 'update', data: '更新的数据' });
}
</script>
</body>
</html>
标签页 B 的代码
<!DOCTYPE html>
<html>
<head>
<title>Page B</title>
</head>
<body>
<script>
const channel = new BroadcastChannel('my_channel');
channel.onmessage = (event) => {
console.log('标签页B接受消息:', event.data);
//接受对象
if (event.data.type === 'update') {
console.log('标签页B接受update类型消息:', event.data.data);
}
};
</script>
</body>
</html>
BroadcastChannel通讯优点
- 实时性好:消息几乎是实时传递的,适用于需要即时通讯的场景
- 使用简单:不需要复杂的设置,易于实现和维护
- 跨上下文:支持
标签页
、iframe
、Worke
r 和Service Worker
之间的通讯,适用范围广
BroadcastChannel通讯缺点
- 不持久化:消息不会持久化,页面刷新或关闭后,之前的消息无法再获取
- 同源限制:只能在同源上下文之间通讯,不同来源无法相互通讯
第三种:SharedWorker
SharedWorker
是一种允许多个浏览器上下文(如标签页
、iframe
)共享一个 Worker
实例的技术,能够实现跨多个上下文的通讯和数据共享。通过 SharedWorker
我们可以在同一来源(同一协议、主机名和端口号)下的不同浏览器上下文之间进行高效的通讯
SharedWorker 的基本概念
- SharedWorker 实例:多个上下文共享一个
Worker
实例,所有上下文可以通过这个Worker
实例进行通讯- 连接和通讯:每个上下文通过
port
对象与SharedWorker
通讯,port
是MessagePort
的实例- 消息传递:通过
postMessage
方法发送消息,通过onmessage
事件处理器接收消息SharedWorker 的特点
- 共享实例:多个上下文共享一个
Worker
实例,节省资源- 双向通讯:通过
MessagePort
实现双向通讯- 同源策略:确保安全性,只有同源的上下文才能相互通讯
基本用法
创建和连接 SharedWorker:在 JavaScript
文件中定义 SharedWorker
脚本
// sharedWorker.js
self.onconnect = function(event) {
const port = event.ports[0];
port.onmessage = function(event) {
// 处理来自页面的消息
console.log('接收来自页面的消息:', event.data);
// 可以将消息发送给其他连接的端口
port.postMessage('来自SharedWorker的回复');
};
};
在 HTML 页面中创建并连接 SharedWorker
// 页面 A 和页面 B 中的代码
const sharedWorker = new SharedWorker('sharedWorker.js');
const port = sharedWorker.port;
// 发送消息
port.postMessage('Hello from Page');
// 接收消息
port.onmessage = (event) => {
console.log('Received from SharedWorker:', event.data);
};
示例代码
编写一个 SharedWorker
脚本 sharedWorker.js
let connections = [];
self.onconnect = function(event) {
const port = event.ports[0];
connections.push(port);
port.onmessage = function(event) {
console.log('Received from page:', event.data);
// 广播消息给所有连接的端口
connections.forEach(conn => {
if (conn !== port) {
conn.postMessage(event.data);
}
});
};
port.start();
};
标签页 A 的代码
<!DOCTYPE html>
<html>
<head>
<title>页面 A</title>
</head>
<body>
<button onclick="sendMessage()">发送页面A消息</button>
<script>
const sharedWorker = new SharedWorker('sharedWorker.js');
const port = sharedWorker.port;
port.start();
function sendMessage() {
port.postMessage('这是来自页面A的消息');
}
port.onmessage = (event) => {
console.log('接收来自SharedWorker的消息:', event.data);
};
</script>
</body>
</html>
标签页 B 的代码
<!DOCTYPE html>
<html>
<head>
<title>Page B</title>
</head>
<body>
<button onclick="sendMessage()">发送页面B消息</button>
<script>
const sharedWorker = new SharedWorker('sharedWorker.js');
const port = sharedWorker.port;
port.start();
function sendMessage() {
port.postMessage('这是来自页面B的消息');
}
port.onmessage = (event) => {
console.log('接收来自SharedWorker的消息:', event.data);
};
</script>
</body>
</html>
SharedWorker优点
- 高效资源利用:共享一个
Worker
实例,减少内存和CPU
占用- 灵活的消息处理:可以在
Worker
中集中处理和分发消息,适用于复杂的通讯需求- 持久连接:连接建立后可以长时间保持,不需要频繁建立和销毁连接
SharedWorker缺点
- 实现复杂:相比
BroadcastChannel
,实现起来稍微复杂一些- 同源限制:只能在同源上下文之间通讯,不同来源无法相互通讯
- 浏览器支持:部分旧版浏览器可能不支持
SharedWorker
结语
到这里博主已经详细介绍了三种常见的浏览器标签页通讯方式,包括 localStorage
事件、BroadcastChannel API
和 SharedWorker
,这些技术各有优劣,小伙伴可以根据实际需求选择合适的解决方案,以实现高效的标签页间通讯。
文中的代码样例大家可以直接复制测试运行效果,如果本文对您有所帮助,希望 一键三连 给博主一点点鼓励,如果您有任何疑问或建议,请随时留言讨论!