SharedWorker 实例需同源且路径完全一致才可共享,file:// 协议不支持,相对路径易致多实例;Safari 对端口更敏感;必须显式调用 port.start() 才能收消息;self 是全局对象,调试需用专用面板;全局变量共享但非线程安全,需自行处理竞态。

SharedWorker 实例必须同源且路径一致才能共享
不同页面调用 new SharedWorker('worker.js') 时,只有协议、域名、端口、路径**完全相同**,浏览器才复用同一个实例。比如 http://localhost:3000/a/worker.js 和 http://localhost:3000/b/worker.js 是两个独立实例,状态互不干扰。
常见踩坑点:
- 开发时用
file://协议 —— SharedWorker 直接不可用(仅支持https或localhost) - 路径写成相对路径如
'./shared-worker.js',但页面 A 在/cart、页面 B 在/profile,实际加载 URL 不同,导致多个 Worker 实例并存 - Safari 要求更严格:即使端口不同(如
localhost:3000vslocalhost:3001),也视为跨源,拒绝共享
页面端必须显式调用 port.start() 才能收消息
创建 SharedWorker 后,worker.port 默认处于“暂停”状态。若没绑定 onmessage 或没手动启动,消息会进队列但不触发回调,造成“发了没反应”的假象。
正确写法:
立即学习“前端免费学习笔记(深入)”;
const worker = new SharedWorker('cart-worker.js');
// 必须先 start(),再监听
worker.port.start();
worker.port.onmessage = (e) => {
console.log('收到广播:', e.data);
};
// 发送消息前也要确保 port 已连接
worker.port.postMessage({ type: 'add', id: 'item-123' });
注意:
- 如果提前绑定了
onmessage,部分浏览器会自动调用start();但不能依赖此行为,显式调用最稳妥 - 页面卸载时无需强制
close(),但可加beforeunload清理监听器,避免内存泄漏
SharedWorker 脚本里没有 window,调试要换方式
self 是 SharedWorker 全局对象,console、fetch、setTimeout 可用,但 alert、document、localStorage(需注意同源限制)均不可用。直接写 console.log() 不会出现在页面控制台,而是在专用 Worker 面板。
调试方法:
- Chrome / Edge:访问
chrome://inspect→ 点击 “Shared workers” 下对应项的inspect - Firefox:
about:debugging#/runtime/this-firefox→ 展开 “Shared Workers” - 不要在脚本里写
self.close()—— 它不会终止 Worker,反而可能中断当前端口通信
全局变量共享但无锁,竞态必须自己处理
SharedWorker 脚本中声明的 let count = 0 或 const cache = new Map() 是所有连接页面共用的,但 JS 执行是单线程,**不等于线程安全**:多个页面同时 postMessage({ type: 'inc' }),count++ 仍可能丢失更新。
简单防竞态建议:
- 用标记位临时阻塞:收到消息时设
isBusy = true,处理完再置false,后续消息排队或丢弃 - 用
self.clients.matchAll()获取当前活跃客户端数,做轻量协调(如只允许第一个页面触发同步) - 关键逻辑尽量原子化:例如把“读-改-写”合并为一条操作,避免中间状态暴露
真正需要强一致性的场景(如金融类计数),SharedWorker 不是银弹;它适合容忍短暂不一致的协同逻辑,比如购物车数量、在线人数、通知开关。



















