# 1 跨标签页通讯

⚡ 30 秒速记

  • 同源首选 BroadcastChannel:语义直接,同频道名的所有同源上下文都能收到(发送方自己不触发)
  • storage 事件兼容性最广,但要借 localStorage 传消息;两个坑:只通知其他页面同值不触发(要带时间戳)
  • SharedWorker 适合"多个标签页共用一条 WebSocket 连接"这类需要共享状态的场景
  • 需要跨设备/跨浏览器时才用服务端通道(WebSocket/SSE)——纯前端方案的天花板是"同一浏览器内的同源页面"
  • cookie + setInterval 轮询是过时写法:有延迟、持续耗 CPUcookie 还跟着每个请求上传

同源标签页之间我一般优先用 BroadcastChannel,需要跨设备时才考虑服务端的 WebSocketSSE 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

webapp
公众号
开发者导航
切换夜间模式
点击侧边栏上一篇
点击侧边栏下一篇
折叠侧边栏
收起全部