shared worker 无法自动统计标签页数量,需页面与 worker 协同实现活跃窗口计数:页面加载时 register、卸载时 unregister;worker 通过 port.onclose 和心跳超时机制保障准确性,并广播最新计数值;需注意 https/同源限制及 safari 兼容性。

Shared Worker 本身不提供“当前打开多少个标签页”的自动统计能力,但可以通过页面主动注册与注销,配合 Worker 内部状态管理,实现一个轻量、可广播的活跃窗口计数器。
计数逻辑必须由页面和 Worker 协同完成
Worker 不会感知页面是否关闭或崩溃,也不能自动发现新标签。必须依赖每个页面在生命周期关键节点发送明确指令:
- 页面加载完成时,通过
port.postMessage({ type: "register" })告知 Worker 自己上线 - 页面即将卸载(
beforeunload或pagehide)时,发送{ type: "unregister" } - Worker 收到后增减全局计数器(如
let activeCount = 0),并调用broadcastCount()向所有端口推送最新值
需处理页面异常退出导致的计数偏差
用户强制关闭标签、浏览器崩溃、或网络中断,都可能让 unregister 消息发不出,造成计数虚高:
- Worker 可监听
port.onclose事件,在端口断开时自动清理对应注册(比仅靠页面发消息更可靠) - 为每个 port 绑定唯一 clientId,并记录其最后通信时间;定时扫描超时(如 30 秒无消息)的 port 并移除
- 不依赖单次 unregister,而是以“端口存活”为真实依据,避免计数漂移
广播更新要兼顾实时性与性能
计数变化不是高频事件,但需确保所有页面及时获知:
- 使用
ports.forEach(port => port.postMessage({ type: "count", value: activeCount }))主动广播 - 避免在每次 register/unregister 后都做深拷贝或复杂计算,保持逻辑扁平
- 页面端只需监听
worker.port.onmessage,提取data.value更新 UI,无需额外状态同步
实际部署要注意兼容性与安全上下文
该方案依赖 Shared Worker 正常启动,而它对运行环境有硬性要求:
- 必须运行在 https 或
http://localhost下,file://协议直接失败且无提示 - Safari 仅支持 macOS 13.3+ / iOS 16.4+,旧版本需 fallback 到单页独立计数或禁用功能
- 所有页面 URL 必须同源(协议、域名、端口完全一致),否则 new SharedWorker() 会静默创建新实例,失去共享意义











