SharedWorker是浏览器提供的多页面共享后台线程机制,与Worker(DedicatedWorker)核心区别在于:前者可被同源下多个页面/iframe共用同一实例,后者仅限创建它的脚本独占使用。

SharedWorker 是什么,和 Worker 有什么区别
SharedWorker 是浏览器提供的多页面共享的后台线程机制,和 Worker(即 DedicatedWorker)最核心的区别在于:一个 SharedWorker 实例可被同一源(origin)下多个页面、iframe 甚至其他 SharedWorker 同时连接,而每个 Worker 只能被创建它的脚本独占使用。
这意味着如果你有 tab A 和 tab B 都加载了同一应用,它们想共用一份状态(比如实时计数器、WebSocket 连接、缓存同步),SharedWorker 就是唯一原生支持的方案;用普通 Worker 每个 tab 都会起一份,互相隔离。
注意:SharedWorker 不支持 document、window 等 DOM API,也不能直接操作页面,它只负责逻辑与通信。
如何正确创建并连接 SharedWorker
创建 SharedWorker 必须传入一个独立的 JS 脚本路径(不能是内联字符串或 blob URL),且该脚本必须通过 HTTP(S) 加载(file:// 协议下多数浏览器直接禁用)。
立即学习“前端免费学习笔记(深入)”;
// main.js(页面中)
const worker = new SharedWorker('worker.js');
worker.port.start(); // 必须显式调用 start()
worker.port.postMessage({ type: 'init', data: 'hello' });
<p>worker.port.onmessage = function(e) {
console.log('来自 SharedWorker 的消息:', e.data);
};关键点:
-
SharedWorker构造后不会自动启动线程,必须通过port.start()建立通信通道 - 所有通信都走
port对象,不是直接postMessage到worker - 多个页面连接同一个
SharedWorker时,每个连接都会触发一次connect事件,在 worker 脚本里要监听它
SharedWorker 脚本里怎么响应多个端口
SharedWorker 的主脚本(如 worker.js)运行在独立上下文中,全局对象是 self,但没有 self.onmessage —— 它用的是 self.onconnect。
// worker.js
self.onconnect = function(e) {
const port = e.ports[0];
port.start(); // 同样需要 start()
<p>port.onmessage = function(msg) {
console.log('收到页面消息:', msg.data);
port.postMessage({ ack: true, from: 'shared-worker' });
};
};常见错误:
- 忘记
port.start()→ 消息发不出去,也不触发onmessage - 在
onconnect外写self.onmessage→ 完全不生效 - 把多个
port当成同一个处理,没做区分 → 导致消息错发给错误页面 - 用
port.close()过早关闭 → 页面再发消息会静默失败(无报错)
SharedWorker 的兼容性与实际限制
SharedWorker 在 Chrome、Edge、Firefox 中可用,但 Safari 完全不支持(截至 Safari 17.6),且 iOS 全系无例外。这意味着如果你的应用需跨平台,不能把它当作核心通信机制,只能作为可选优化。
另外几个硬限制:
- 同一 origin 下,相同 script URL 的
SharedWorker实例自动复用,但 URL 中 query 参数不同(如worker.js?v=2)会被视为不同实例 - 无法从
Service Worker或Web Worker内部创建SharedWorker -
SharedWorker无法访问localStorage、indexedDB等存储 API(需通过 port 转发请求到页面代理) - 页面关闭时,对应
port会断开,但SharedWorker实例本身不会立即销毁——只有所有连接都断开后,浏览器才可能回收它(时间不可控)
SharedWorker 的“共享”是隐式的、基于 URL 的,一旦路径或协议稍有差异(比如 http vs https,www vs 非 www),就完全隔离。这点很容易被忽略,调试时发现“为什么两个 tab 没共享”,八成是 origin 不一致。



















