shared worker 无法直接统计标签数,但可通过页面注册/注销配合全局计数器实现:worker 维护 activecount 并广播,页面在加载时发 register、卸载时发 unregister,需注意同源路径、刷新行为及异常退出导致的计数偏差。

Shared Worker 本身不直接提供“当前打开标签数”的实时统计能力,但可以通过全局计数器配合消息通信机制,在多个页面与 Shared Worker 之间协同维护一个共享的标签计数。关键在于:每个页面在连接时主动注册、断开时主动注销,Worker 统一增减计数并广播最新值。
1. Shared Worker 中维护全局计数器
Shared Worker 的作用域是整个 origin(协议+域名+端口),其脚本只运行一次,天然适合做跨标签共享状态。用一个闭包变量 activeCount 记录当前活跃标签数,并监听来自各页面的 connect 和自定义消息(如 "register" / "unregister"):
(worker.js)
let activeCount = 0;
const ports = new Set();
<p>self.onconnect = function(e) {
const port = e.ports[0];
ports.add(port);</p><p>port.onmessage = function(event) {
const { type } = event.data;
if (type === 'register') {
activeCount++;
broadcastCount();
} else if (type === 'unregister') {
activeCount = Math.max(0, activeCount - 1);
broadcastCount();
}
};</p><p>port.start(); // 必须调用
};</p><p>function broadcastCount() {
ports.forEach(port => {
port.postMessage({ type: 'count', value: activeCount });
});
}
</p>
2. 页面端主动注册与生命周期绑定
每个页面需在加载时连接 Shared Worker 并发送 register,并在卸载前发送 unregister。注意:不能仅依赖 beforeunload,因标签可能被强制关闭或崩溃;建议结合 visibilitychange 做更健壮的保活判断(可选进阶):
- 使用
new SharedWorker('./worker.js')创建连接 - 调用
worker.port.postMessage({ type: 'register' })注册 - 监听
worker.port.onmessage获取实时计数更新 - 在
beforeunload或pagehide中发送unregister
(page.js)
const worker = new SharedWorker('./worker.js');
const port = worker.port;
<p>port.onmessage = function(e) {
if (e.data.type === 'count') {
console.log('当前打开标签数:', e.data.value);
document.getElementById('tab-count').textContent = e.data.value;
}
};</p><p>port.postMessage({ type: 'register' });</p><p>// 页面即将离开时注销
window.addEventListener('beforeunload', () => {
port.postMessage({ type: 'unregister' });
});
// 或更兼容的 pagehide(支持 Android Chrome 等)
window.addEventListener('pagehide', () => {
port.postMessage({ type: 'unregister' });
});
</p>
3. 注意事项与边界情况处理
该方案看似简单,但实际部署需关注几个易错点:
- Worker 脚本路径必须同源且相对路径一致,否则浏览器会创建多个独立 Worker 实例,计数失效
- 页面刷新时会触发 register → unregister → register 流程,计数短暂归零再恢复,属正常行为
- 页面崩溃或异常退出时 unregister 可能未发出,导致计数偏高;可通过 Worker 内定时检查 port.readyState(但不可靠),或引入超时自动清理(需复杂心跳机制,一般场景可忽略)
-
Service Worker 干扰:若已注册 Service Worker 拦截了 worker.js 请求,需确保其正确返回该脚本(
response.headers.set('Content-Type', 'application/javascript'))
4. 验证与调试技巧
快速验证是否生效:
- 打开两个相同页面,观察控制台输出的
count是否为 2 - 关闭一个标签,确认另一标签收到
count: 1 - 在 Shared Worker 控制台(Chrome DevTools → Application → Shared Workers)中点击 “Inspect”,查看
console.log输出(可在 worker.js 中加日志) - 用
chrome://inspect/#workers查看所有活跃 Shared Worker 实例及连接端口数










