SharedWorker 和 Broadcast Channel 都可用于处理跨标签页通信,但二者在功能与适用场景上存在显著差异:
Broadcast Channel 类似于一个公共广播系统,只能进行“一对多”的消息发布。它无法指定特定的接收者,也无法控制消息的接收顺序,更无法接收来自监听方的反馈或响应。换句话说,它只支持单向、无状态的消息广播。
SharedWorker 则不仅具备广播消息的能力,还能实现更精细的控制。它可以 指定特定的对象接收消息,支持 按顺序传递消息,甚至能够 接收并处理来自接收方的反馈信息,从而实现双向、有状态的通信。
广播消息: 一个页面发送消息,让其它访问相同网站的页面接收消息。
写一个 SharedWorker 脚本 sw.js 文件,维护一个端口池(port pool),当某个页面发送消息时,Worker 遍历所有已连接的端口,将消息转发给每一个端口,从而实现广播效果。
// 存储所有连接的端口
const connections = []
// 监听到标签页连接 SharedWorker 会进入该方法
self.onconnect = (e) => {
const port = e.ports[0]
connections.push(port)
console.log('新客户端连接,当前连接数:', connections.length)
// 监听到标签页发送消息会进入该方法
port.onmessage = (event) => {
// 广播消息给所有连接的页面
connections.forEach(p => {
p.postMessage({
from: 'Broadcast',
data: event.data, // event.data 接收消息
timestamp: Date.now()
})
})
}
port.start()
}
写一个 index.html 文件用于测试
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>SharedWorker 广播 - 发送页面</h1>
<input type="text" id="messageInput" placeholder="输入要广播的消息">
<button onclick="broadcastMessage()">发送广播</button>
<div id="receivedMessages"></div>
<script>
// 创建 SharedWorker
const worker = new SharedWorker('./sw.js')
console.log('worker', worker)
worker.port.start()
// 发送广播消息
function broadcastMessage() {
const msg = document.getElementById('messageInput').value
worker.port.postMessage(msg)
document.getElementById('messageInput').value = ''
}
// 接收广播消息
worker.port.onmessage = (e) => {
const messagesDiv = document.getElementById('receivedMessages')
messagesDiv.innerHTML += `<p>收到广播: ${e.data.data}</p>`
}
</script>
</body>
</html>
到目前为止,准备工作已经完成。需要注意的是,不能直接在浏览器中通过 file:// 协议打开 HTML 文件,因为 SharedWorker 必须在 HTTPS 或 localhost 环境下才能正常注册。
接下来,我们使用 http-server 创建一个本地 Web 服务器环境:
$ npx http-server . -p 8080
然后在浏览器中打开两个标签页,均访问 http://localhost:8080/index.html。在其中一个标签页中修改文本框的值并点击“发送广播”,在另一个标签页中可以看到消息已经成功更新。
补充说明:由于 SharedWorker 中的 console.log 不会显示在页面的控制台中,需要通过以下方式进行调试:在浏览器地址栏访问 chrome://inspect/#workers,在该页面中可以查看当前已创建的 SharedWorker。点击其中的 inspect 链接,即可进入独立的调试控制台。
↶ 返回首页 ↶