# 1 跨标签页通讯
⚡ 30 秒速记
- 同源首选
BroadcastChannel:语义直接,同频道名的所有同源上下文都能收到(发送方自己不触发) storage事件兼容性最广,但要借localStorage传消息;两个坑:只通知其他页面、同值不触发(要带时间戳)SharedWorker适合"多个标签页共用一条WebSocket连接"这类需要共享状态的场景- 需要跨设备/跨浏览器时才用服务端通道(
WebSocket/SSE)——纯前端方案的天花板是"同一浏览器内的同源页面" cookie+setInterval轮询是过时写法:有延迟、持续耗CPU、cookie还跟着每个请求上传
同源标签页之间我一般优先用 BroadcastChannel,需要跨设备时才考虑服务端的 WebSocket 或 SSE。 BroadcastChannel 语义直接,但发送方自身不会收到消息;兼容旧环境可用 storage 事件兜底,并给消息加时间戳避免同值不触发。多个标签页需要共享状态或复用一条长连接时,SharedWorker 更合适,但调试和兼容性需要取舍。有父子窗口关系也能用 postMessage,同时必须校验 origin。
跨标签页通信要先分两类场景:同源的纯浏览器通信,和需要服务端中转的跨设备同步。
① BroadcastChannel(同源首选)
const channel = new BroadcastChannel('auth')
channel.postMessage({ type: 'logout' }) // A 标签页发
channel.onmessage = (e) => { ... } // B 标签页收(发送方自己不触发)
window.addEventListener('pagehide', () => channel.close())
语义最直接:同一个频道名的所有同源上下文都能收到。
② storage 事件(兼容性最广)
localStorage.setItem('msg', JSON.stringify({ type: 'logout', t: Date.now() }))
window.addEventListener('storage', (e) => { if (e.key === 'msg') { /* ... */ } })
两个坑:只通知其他标签页(自己不触发)、同值不触发(连发两次一样的内容第二次收不到,所以要带时间戳)。它本质是"用存储的副作用做通信",能用 BroadcastChannel 就别用它。
③ SharedWorker(需要共享状态时)
多个标签页连到同一个 Worker 实例,适合"多个页面共用一条 WebSocket 连接"——避免开十个标签就建十条连接。代价是调试麻烦、Safari 支持长期缺失。
④ window.opener + postMessage