# 1 跨标签页通讯

⚡ 30 秒速记

  • 同源首选 BroadcastChannel:同频道名的同源页面都能收到,发送方自己收不到
  • storage 事件兼容最广,两个坑:只通知其他页面、写入同值不触发(带时间戳)
  • SharedWorker 适合多个标签页共用一条 WebSocket;Safari 16 才重新支持,上线前查兼容
  • 有父子关系的窗口用 postMessage,接收方必须校验 event.origin
  • 跨浏览器、跨设备只能走服务端 WebSocket / SSE;cookie + setInterval 轮询是过时写法

同一个浏览器里的同源标签页,我首选 BroadcastChannel,跨设备才上服务端推送。 BroadcastChannel 就像一个同源页面共享的对讲频道,一个页面 postMessage,同频道的其他页面 onmessage 都能收到,最典型的用法是一处退出、所有标签页一起登出。要兼容很老的浏览器就用 storage 事件兜底,但它本质是借存储的副作用通信,同值不触发,所以消息里要带时间戳。如果目标是多个页面共享一条长连接,那就是 SharedWorker 的活。

时序图 · 4 个参与者 / 9 步
alt 支持 BroadcastChannel老浏览器标签页 A标签页 Aauth 频道auth 频道标签页 B标签页 B服务端服务端调用退出接口1会话已注销2本页清状态并跳登录页3postMessage logout4发送方自己收不到广播onmessage 收到 logout5清本地状态,跳登录页6写 localStorage 触发 storage 事件7读到带时间戳的 logout 并处理8pagehide 时 close 频道9

跨标签页通信要先分两类场景:同源的纯浏览器通信,和需要服务端中转的跨设备同步。

① 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') { /* ... */ } })
webapp
公众号
开发者导航
切换夜间模式
点击侧边栏上一篇
点击侧边栏下一篇
折叠侧边栏
收起全部