-
• 浏览器跨标签页通信
-
• Broadcast Channel API:
-
• LocalStorage/SessionStorage:
-
• SharedWorker:
-
• Cookies + setInterval:
-
• WebSocket:
-
• postMessage (适用于同源或跨源场景,如 iframe、窗口间通信):
-
• IndexedDB
-
• 服务器端存储
浏览器跨标签页通信
浏览器跨标签页通信是指在同一个浏览器进程中,不同标签页之间进行数据交换和消息传递。
由于浏览器默认将每个标签页视为独立的执行环境(即每个标签页有自己的全局作用域和事件循环),它们之间不能直接访问彼此的内存空间或变量。
然而,为了满足一些应用场景的需求,如实时状态同步、协同编辑、通知传递等,开发者可以利用浏览器提供的API和机制实现跨标签页通信。
以下是实现这一目标的常见方式,包括技术原理和简要示例:
Broadcast Channel API:
-
• 原理:Broadcast Channel API 提供了一个内置通道,允许来自同一源(相同协议、主机名和端口)的多个浏览上下文(如标签页、窗口、服务工作线程)进行双向通信。
-
• 示例:
// 发送消息的标签页
const channel = new BroadcastChannel('my-channel');
channel.postMessage({ message: 'Hello from tab A' });
// 接收消息的标签页
const channel = new BroadcastChannel('my-channel');
channel.addEventListener('message', (event) => {
console.log(`Received message: ${event.data.message}`);
});
LocalStorage/SessionStorage:
-
• 原理:这两个浏览器存储API提供了在同一浏览器实例中跨标签页共享数据的能力。当数据发生变化时,会触发
storage
事件,其他标签页可以通过监听此事件来获取更新。 -
• 示例:
// 写入数据的标签页
localStorage.setItem('sharedData', JSON.stringify({ key: 'value' }));
// 监听数据变化的标签页
window.addEventListener('storage', (event) => {
if (event.key === 'sharedData') {
const data = JSON.parse(event.newValue);
console.log(`Updated data: ${data.key}`);
}
});
-
• 原理:SharedWorker 是一种可以被多个浏览器上下文共享的 Web Worker 实例,它创建一个独立的线程,使得多个标签页可以通过与该 Worker 通信来互相交互。
-
• 示例:
// SharedWorker 脚本(shared-worker.js)
self.onconnect = function(e) {
const port = e.ports[0];
port.onmessage = function(e) {
console.log(`Received from tab: ${e.data}`);
// 广播给所有连接的标签页
port.postMessage(`Message from SharedWorker: ${e.data}`);
};
};
// 在各个标签页中连接到 SharedWorker
const worker = new SharedWorker('shared-worker.js');
worker.port.addEventListener('message', (event) => {
console.log(`Received from SharedWorker: ${event.data}`);
});
worker.port.start();
worker.port.postMessage('Hello from tab');
Cookies + setInterval:
-
• 原理:利用 cookies 存储跨标签页共享的信息,并通过定时器定期检查 cookie 值的变化来实现通信。
-
• 示例:
// 设置 cookie 的标签页
document.cookie = 'crossTabMessage=Hello%20from%20tab%20A';
// 检查 cookie 更新的标签页
function checkCookieChanges() {
const currentCookie = document.cookie.replace(/(?:(?:^|.*;s*)crossTabMessages*=s*([^;]*).*$)|^.*$/, "$1");
if (currentCookie !== lastCookieValue) {
console.log(`Received cookie message: ${currentCookie}`);
lastCookieValue = currentCookie;
}
}
let lastCookieValue = '';
setInterval(checkCookieChanges, 1000); // 每秒检查一次
WebSocket:
-
• 原理:WebSocket 是一种全双工的网络协议,允许服务器与客户端建立持久的连接并双向实时通信。虽然主要用于浏览器与服务器间的通信,但可以通过服务器作为中介实现跨标签页通信。
-
• 示例(简化版,未包含服务器部分):
// 所有标签页连接到同一 WebSocket 服务器
const socket = new WebSocket('ws://example.com/socket');
socket.addEventListener('message', (event) => {
console.log(`Received message from server: ${event.data}`);
});
// 当某个标签页需要发送消息时
socket.send('Hello from tab');
postMessage (适用于同源或跨源场景,如 iframe、窗口间通信):
-
• 原理:
window.postMessage()
方法允许来自不同源的脚本采用安全的方式进行通信。尽管您提到的问题是关于跨标签页通信,但这里也提及postMessage
以涵盖可能的上下文,如嵌入的 iframe 之间的通信。 -
• 示例(假设两个同源标签页间通信):
// 发送消息的标签页
otherWindow = window.open('other-page.html');
otherWindow.postMessage({ message: 'Hello from tab A' }, '*');
// 接收消息的标签页
window.addEventListener('message', (event) => {
if (event.origin === 'https://example.com') { // 验证来源
console.log(`Received message: ${event.data.message}`);
}
});
IndexedDB
-
• 原理:
IndexedDB
是浏览器提供的一个客户端数据库,可以在不同的标签页之间存储和读取数据。 -
• 一个标签页可以将数据写入 IndexedDB,其他标签页可以监听 IndexedDB 的变化事件或定时从 IndexedDB 中读取数据来实现数据的共享和状态的同步。
// 打开或创建IndexedDB数据库
const request = indexedDB.open('myDatabase', 1);
// 成功打开数据库
request.onsuccess = function(event) {
const db = event.target.result;
// 创建一个对象存储空间(类似表)
const objectStore = db.createObjectStore('messages', { keyPath: 'id', autoIncrement: true });
// 添加一条消息到对象存储空间
const message = { text: 'Hello, World!' };
const addRequest = objectStore.add(message);
addRequest.onsuccess = function(event) {
console.log('消息已添加到IndexedDB');
};
addRequest.onerror = function(event) {
console.error('添加消息到IndexedDB时发生错误');
};
// 从对象存储空间获取所有消息
const getAllRequest = objectStore.getAll();
getAllRequest.onsuccess = function(event) {
const messages = event.target.result;
console.log('所有消息:', messages);
};
getAllRequest.onerror = function(event) {
console.error('获取消息时发生错误');
};
};
// 打开或创建数据库时发生错误
request.onerror = function(event) {
console.error('打开/创建数据库时发生错误');
};
// 数据库版本变更
request.onupgradeneeded = function(event) {
const db = event.target.result;
// 创建一个对象存储空间
const objectStore = db.createObjectStore('messages', { keyPath: 'id', autoIncrement: true });
console.log('数据库版本已更新');
};
服务器端存储
将需要共享的数据存储在服务器端,标签页之间通过与服务器进行通信来获取和更新数据。可以使用 AJAX、WebSocket 或其他网络通信技术来实现与服务器的数据交互。
综上所述,浏览器内跨标签页通信可以通过 Broadcast Channel API、LocalStorage/SessionStorage、SharedWorker、Cookies + setInterval、WebSocket、以及在特定场景下的 postMessage 等方式实现。
选择何种方式取决于实际需求,如数据同步的实时性、是否需要服务器中介、是否涉及跨源通信等。
BroadcastChannel
MDN 地址:https://developer.mozilla.org/zh-CN/docs/Web/API/BroadcastChannel
BroadcastChannel接口代理了一个命名频道,可以让指定 origin 下的任意 browsing context 来订阅它。
它允许同源的不同浏览器窗口,Tab 页,frame 或者 iframe 下的不同文档之间相互通信。
通过触发一个 message 事件,消息可以广播到所有监听了该频道的 BroadcastChannel 对象。
MDN地址:https://developer.mozilla.org/zh-CN/docs/Web/API/SharedWorker
SharedWorker 接口代表一种特定类型的 worker,可以从几个浏览上下文中访问,例如几个窗口、iframe 或其他 worker。
它们实现一个不同于普通 worker 的接口,具有不同的全局作用域,SharedWorkerGlobalScope 。
备注: 如果要使 SharedWorker 连接到多个不同的页面,这些页面必须是同源的(相同的协议、host 以及端口)
window.postMessage
MDN地址:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage
window.postMessage() 方法可以安全地实现跨源通信。
通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为 https),端口号(443 为 https 的默认值),以及主机 (两个页面的模数 Document.domain设置为相同的值) 时,这两个脚本才能相互通信。
window.postMessage() 方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。
从广义上讲,一个窗口可以获得对另一个窗口的引用(比如 targetWindow = window.opener),然后在窗口上调用 targetWindow.postMessage() 方法分发一个 MessageEvent 消息。接收消息的窗口可以根据需要自由处理此事件 (en-US)。传递给 window.postMessage() 的参数(比如 message)将通过消息事件对象暴露给接收消息的窗口。
原文始发于微信公众号(前端爱好者):简说浏览器跨标签页通信方式
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/272572.html