shared worker 的 connect 事件在每个独立上下文(如标签页、iframe)首次连接时触发一次,需通过 self.addeventlistener('connect') 监听,获取 event.ports[0] 并调用 port.start() 启动通信,再通过 message 事件处理消息;页面应主动发送 init 消息标识自身,worker 用 map 管理客户端,配合 beforeunload 发送 bye 消息实现主动断开管理。

Shared Worker 的 connect 事件用于监听新页面(或 iframe)首次连接到该 Shared Worker 的时刻。它不是每次消息都触发,而是每个独立的上下文(如一个标签页、一个 iframe)在调用 new SharedWorker() 并成功建立连接时触发一次。
connect 事件的基本监听方式
在 Shared Worker 的脚本中(即传给 new SharedWorker('worker.js') 的那个 JS 文件),通过全局对象 self 监听 connect:
- 事件只在连接建立时触发,不是每发一条消息都触发
- 回调函数接收一个
event对象,其source属性是该页面对应的MessagePort - 必须手动调用
port.start()才能收发消息(如果使用addEventListener方式注册)
示例(shared-worker.js):
self.addEventListener('connect', (event) => {
const port = event.ports[0];
// 必须启动端口才能通信
port.start();
console.log('新页面接入,共', self.clients.length, '个活跃客户端');
// 可选:发送欢迎消息
port.postMessage({ type: 'welcome', id: Math.random().toString(36).substr(2, 6) });
// 监听该页面发来的消息
port.addEventListener('message', (msgEvent) => {
console.log('收到来自该页面的消息:', msgEvent.data);
port.postMessage({ echo: msgEvent.data });
});
});
如何识别和管理多个接入页面
Shared Worker 本身不直接暴露“页面 URL”或“标签页 ID”,但你可以让页面在首次连接时主动发送标识信息:
- 页面连接后,立即通过
port.postMessage()发送自身信息(如location.href、document.title或自定义 ID) - Worker 中可维护一个
Map,以port为 key,存储该页面的元数据 - 注意:
port是唯一且稳定的(同一页面内不会变),但页面刷新后会断开并新建连接
Worker 端增强示例:
const clients = new Map();
self.addEventListener('connect', (event) => {
const port = event.ports[0];
port.start();
// 等待页面发来初始化信息(带 id 或 url)
const initHandler = (msgEvent) => {
if (msgEvent.data?.type === 'init') {
const clientId = msgEvent.data.clientId || Date.now() + '-' + Math.random().toString(36).substr(2, 4);
clients.set(port, {
id: clientId,
url: msgEvent.data.url || '(unknown)',
connectedAt: Date.now()
});
console.log(`页面 [${clientId}] 已接入: ${msgEvent.data.url}`);
port.postMessage({ type: 'ready', clientId });
port.removeEventListener('message', initHandler);
}
};
port.addEventListener('message', initHandler);
});
对应页面端需在连接后立刻初始化:
const worker = new SharedWorker('shared-worker.js');
worker.port.start();
worker.port.postMessage({
type: 'init',
clientId: 'tab-001',
url: location.href
});
注意 disconnect 和客户端生命周期
Shared Worker 没有内置的 disconnect 事件。页面关闭、刷新或显式调用 worker.port.close() 后,port 会失效,但 Worker 不会自动得知——除非你主动设计心跳或超时机制:
- 可让页面定时发送
ping,Worker 记录最后活跃时间,超时则清理对应 entry - 调用
self.clients.matchAll()(需启用clientType: 'sharedworker'的兼容性支持,但目前仅部分浏览器支持) - 更可靠的做法:页面卸载前主动通知(
beforeunload或pagehide)
例如页面端退出通知:
window.addEventListener('beforeunload', () => {
worker.port.postMessage({ type: 'bye', clientId: 'tab-001' });
});
Worker 端配合处理:
port.addEventListener('message', (e) => {
if (e.data?.type === 'bye') {
clients.delete(port);
console.log('页面主动断开:', e.data.clientId);
}
});
常见问题与验证技巧
调试 connect 事件是否生效,可结合以下方式:
- 打开多个同源标签页(必须同协议、域名、端口),每个页面执行
new SharedWorker(...) - 检查浏览器开发者工具 → Application → Shared Workers,查看运行状态和日志
- 在 Worker 脚本开头加
console.log('Worker started'),确认脚本加载无误 - 确保页面与 Worker 脚本同源;跨域会静默失败,且不抛错
- 注意 Service Worker 可能劫持请求,导致 Worker 脚本被缓存旧版本,更新后需硬刷新或禁用缓存调试










