SharedWorker 是一种允许多个浏览上下文共享同一 Worker 实例的 Web API,用于跨标签页通信;需同源且路径一致,通过 port.postMessage/onmessage 双向通信,不支持 file:// 协议,兼容性上 Safari 16.4+ 才支持。

SharedWorker 是浏览器提供的一种 Web Worker 类型,允许**多个浏览上下文(如不同标签页、iframe 或窗口)共享同一个 Worker 实例**,从而实现跨标签页的通信。它比 postMessage 配合 localStorage + storage 事件更可靠、更高效,也比 BroadcastChannel 更早被广泛支持(但注意兼容性差异)。
一、SharedWorker 的基本使用流程
要让多个页面共用一个 SharedWorker,需满足两个关键点:同源(协议、域名、端口一致),且所有页面通过相同路径实例化 SharedWorker。
- 在页面中用
new SharedWorker('worker.js')创建连接;路径必须完全一致(包括查询参数),否则会创建新实例 - SharedWorker 脚本(
worker.js)中监听connect事件,拿到 port 后调用port.start() - 页面与 Worker 之间通过
port.postMessage()和port.onmessage双向通信
二、完整示例:两个标签页同步计数器
注意:SharedWorker 不支持 file:// 协议,必须通过 http/https 服务运行(如用 npx serve 或 VS Code Live Server)
页面代码(index.html):
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
<button id="inc">+1</button>
<span id="count">0</span>
<script>
const worker = new SharedWorker('counter-worker.js');
const port = worker.port;
port.onmessage = (e) => {
document.getElementById('count').textContent = e.data.count;
};
port.start(); // 必须调用
document.getElementById('inc').onclick = () => {
port.postMessage({ type: 'increment' });
};
</script>
SharedWorker 脚本(counter-worker.js):
let count = 0;
const ports = [];
self.onconnect = (e) => {
const port = e.ports[0];
ports.push(port);
port.onmessage = (e) => {
if (e.data.type === 'increment') {
count++;
// 广播给所有已连接的页面
ports.forEach(p => p.postMessage({ count }));
}
};
port.start();
};
三、关键细节和常见问题
-
端口生命周期:每个页面连接对应一个独立
MessagePort,页面关闭时端口自动关闭,Worker 中需监听port.onclose清理(但实际可不处理,因onconnect中的e.ports[0]已是新 port) -
消息作用域隔离:SharedWorker 运行在独立线程和全局环境(
self),无法访问window、document等 DOM API -
错误处理:页面侧监听
worker.onerror,Worker 侧用self.onerror;建议在port.onmessage中加 try-catch 防止单个消息崩溃整个 Worker - 兼容性:Chrome、Edge、Firefox 支持良好;Safari 从 16.4 开始支持(iOS 16.4+),旧版 Safari 不支持,需降级方案(如 BroadcastChannel + localStorage 回退)
四、进阶:支持多类型消息与响应式广播
可在 Worker 中维护一个客户端映射,区分消息来源或支持请求-响应模式:
// 在 counter-worker.js 中扩展
let clientId = 0;
const clients = new Map(); // port → { id, name }
self.onconnect = (e) => {
const port = e.ports[0];
const id = ++clientId;
clients.set(port, { id });
port.onmessage = (e) => {
const { type, payload } = e.data;
if (type === 'register') {
clients.get(port).name = payload.name;
} else if (type === 'getCount') {
port.postMessage({ type: 'count', value: count });
}
};
port.start();
// 页面断开时清理
port.onclose = () => clients.delete(port);
};
这样页面可主动请求当前值,Worker 也能按需向特定端口回复,提升灵活性。

















