shared worker 的核心是“一个线程、多个端口、同源共用”,即同源下所有页面共享唯一后台实例;url 全路径决定唯一性,通信依赖 messageport 和结构化克隆,顶层变量全局共享但需防竞态,适用于登录态同步、websocket 复用等轻量协同场景。
shared worker 的核心就是“一个线程、多个端口、同源共用”。它不是为单页服务的后台脚本,而是浏览器在同源(协议+域名+端口)下自动合并出的唯一后台实例——不管打开 2 个还是 20 个标签页,只要加载的是同一份 shared-worker.js,它们连的都是同一个线程。
同源唯一性是运行前提
Shared Worker 实例由 URL 全路径决定。比如:
-
https://example.com/workers/state.js和https://example.com/workers/state.js?cache=1被视为两个不同 Worker(带查询参数即不同 URL) -
http://localhost:3000/worker.js可用;但http://127.0.0.1:3000/worker.js是另一个源,无法共享 - HTTPS 环境下才被主流浏览器稳定支持;HTTP 只在 localhost 有效
通信靠 MessagePort,不是直接调用
页面和 Shared Worker 之间不共享内存、不暴露函数引用,所有交互必须走结构化克隆 + 消息传递:
- 主页面调用
new SharedWorker('worker.js')得到一个SharedWorker对象,其.port是通信入口 - 必须手动调用
port.start()才能启用双向消息(尤其在未设置onmessage时) - Worker 脚本中监听
self.onconnect,从事件中取出e.ports[0],同样要port.start() - 发送用
port.postMessage(data),接收统一走port.onmessage
状态共享靠全局作用域,但需防竞态
Worker 脚本里的顶层变量(如 let count = 0、const cache = new Map())对所有连接端口可见且共用——这是真正意义上的“共享内存”:
- 多个标签页同时执行
count++可能丢失更新(无原子性),需自行协调,例如用标记位或简单队列 - 可用
self.clients.matchAll()获取当前活跃客户端列表,用于定向广播或状态校验 - Worker 不会因某个页面关闭而终止;只有全部端口断开 + 无定时器/事件监听时,浏览器才回收
适用场景决定架构重心
Shared Worker 不是万能胶,它的价值体现在“轻量协同”上:
- 登录态同步:Worker 维护
isLogin,任一页面登出即广播,其余页面响应跳转 - WebSocket 复用:仅 Worker 内建立一次连接,所有页面通过它收发消息,避免多开连接
- 配置缓存代理:首次请求后存入
state.config,后续页面发{type:'GET_CONFIG'}直接返回,不重复拉取 - 协同计数器:各页面上报“进入/离开”,Worker 统计并广播实时人数











