多年来,由于网络应用程序的需求,Web浏览器的功能不断增强。因此,我们可以找到多种实现类似功能的方式。我们很少关注的一个功能是在浏览器标签之间进行通信的能力。让我们看看一些需要这种功能的情景。
- 更改主程序的主题,同时已打开的浏览器标签页也一起修改。
- 获取最新的身份验证信息,并在浏览器标签之间共享。
- 在浏览器标签页之间同步应用程序状态。
实时跨浏览器标签通信指的是在不同的浏览器标签页之间实现即时的通信和数据传输。这种通信可以用于许多场景,比如在一个应用程序中,用户可能在多个标签页中进行操作,而这些操作需要即时地反映在其他标签页中。
实时跨浏览器标签通信通常涉及以下关键概念:
- 即时性:通信应该是即时的,一旦一个标签页发送了消息或者改变了某些数据,其他标签页应该能够立即接收到这些变化。
- 数据传输:通信可以涉及文本消息、数据对象或者其他类型的信息,这些信息需要能够在不同的标签页之间传递。
- 实时性保证:通信机制应该能够保证在不同标签页之间的实时性,即使在用户不断打开、关闭标签页的情况下也应该能够保持稳定的通信。
- 安全性:通信机制应该确保数据传输的安全性,以防止恶意的数据篡改或窃取。
总的来说,实时跨浏览器标签通信的概念是为了让用户在不同标签页之间能够实时地共享信息和数据,从而提供更流畅、更一致的用户体验。
下面,我将详细讨论可以实现标签通信的各种方法优势和劣势。
本地存储事件(如LocalStorage或IndexedDB)
你可能已经使用过LocalStorage,它可以在同一应用程序来源的标签页之间访问。但你知道它也支持事件吗?你可以利用这个特性在浏览器标签页之间进行通信,其他标签页在存储更新后会接收到事件。
例如,让我们假设在一个标签页中执行以下JavaScript代码。
js
window.localStorage.setItem("loggedIn", "true");
其他监听该事件的标签就会接收到它,如下所示。
js
window.addEventListener('storage', (event) => {
if (event.storageArea != localStorage) return;
if (event.key === 'loggedIn') {
// Do something with event.newValue
}
});
然而,它本身带有一些限制。
- 此事件不会被触发,对于执行存储设置操作的选项卡。
- 对于大量数据,这种方法会产生不利影响,因为LocalStorage是同步的,因此可能会阻塞主UI线程。
Broadcast Channel API
当使用 Broadcast Channel API 时,你可以创建一个频道,并在不同的浏览器标签页之间发送和接收消息。下面是一个简单的示例,演示了如何在两个不同的浏览器标签页之间使用 Broadcast Channel API 进行通信。
广播频道API允许标签页、窗口、框架、内联框架和Web Workers之间进行通信。一个标签页可以按以下方式创建并发布到频道。
js
const channel = new BroadcastChannel('app-data');
channel.postMessage(data);
其他标签可以按以下方式收听频道。
js
const channel = new BroadcastChannel('app-data');channel.addEventListener ('message', (event) => {
console.log(event.data);
});
这种方式可以让浏览器上下文(窗口、标签页、框架或内嵌框架)进行通信。虽然这是浏览器标签页之间进行方便的通信方式,但 Safari 和 IE 不支持这种方式。你可以在 MDN 的 BroadcastChannel 文档中找到更多细节。
Server-Sent Events (SSE)
你可能会想知道,Service Workers是如何介入其中的。基本上,Service Workers也支持发送消息,我们可以利用它来在浏览器标签之间进行通信。
利用Service Workers,你可以发送如下所示的消息。
js
navigator.serviceWorker.controller.postMessage({
broadcast: data
});
在另一个浏览器标签页中的接收工作者可以监听到该事件。
js
addEventListener('message', async (event) => {
if ('boadcast' in event.data ) {
const allClients = await clients.matchAll();
for (const client of allClients) {
client.postMessage(event.broadcast);
}
}
});
这种方法能够更好地控制消息传递,是一种可靠的方式。但是,要实现Service Workers需要对Service Worker API有足够的了解和使用经验。你可以在MDN的Service Worker API文档中找到更多信息。
窗口发布消息(postMessage)
在浏览器标签页、弹出窗口和内联框架之间进行传递信息的传统方式之一是 Window.postMessage()
方法。您可以按照以下方式发送消息。
js
targetWindow.postMessage(message, targetOrigin)
并且目标窗口可以监听事件,如下所示。
js
window.addEventListener("message", (event) => {
if (event.origin !== "http://localhost:8080")
return;
// Do something
}, false);
这种方式的优点是非常灵活,可以在不同的窗口之间进行双向通信,并且可以跨越不同的域。但需要注意的是,由于跨域通信涉及到安全性问题,因此在使用时需要特别小心,确保不会因为跨域通信而引入安全隐患。 因此,这种方法只适用于通过window.open()或document.open()打开的浏览器标签页。你可以在MDN文档中找到更多信息。
结论
除了讨论过的方法,我们还可以使用Websockets和服务器发送事件在浏览器标签之间甚至跨设备进行实时通信。但是,您需要一个Web服务器来使用这些方法。文章中列出的方法不依赖于Web服务器,因此它能快速处理浏览器内的通信。