多标签页通信与数据同步
场景
用户在多个浏览器标签页打开同一个应用,需要在标签页之间同步数据(如登录状态、购物车、主题设置)。
方案对比
| 方案 | 同源限制 | 实时性 | 复杂度 | 兼容性 |
|---|---|---|---|---|
| BroadcastChannel | 同源 | 实时 | 低 | 好 |
| localStorage 事件 | 同源 | 实时 | 低 | 极好 |
| SharedWorker | 同源 | 实时 | 中 | 一般 |
| Service Worker | 同源 | 实时 | 中 | 好 |
| window.postMessage | 跨源 | 实时 | 中 | 极好 |
BroadcastChannel(推荐)
跨标签页通信
// 创建频道(同名频道自动连接)
const channel = new BroadcastChannel('app-sync');
// 发送消息
function broadcast(type: string, data: unknown) {
channel.postMessage({ type, data, timestamp: Date.now() });
}
// 接收消息
channel.onmessage = (e: MessageEvent) => {
const { type, data } = e.data;
switch (type) {
case 'LOGOUT':
// 其他标签页登出,当前页也退出
handleLogout();
break;
case 'THEME_CHANGE':
setTheme(data);
break;
case 'CART_UPDATE':
refreshCart(data);
break;
}
};
// 页面关闭时清理
window.addEventListener('beforeunload', () => channel.close());
localStorage 事件
storage 事件监听
// 当 localStorage 在其他标签页被修改时触发
window.addEventListener('storage', (e: StorageEvent) => {
if (e.key === 'user-session') {
if (e.newValue === null) {
// 其他标签页清除了 session → 登出
handleLogout();
}
}
});
// 注意:storage 事件不会在当前标签页触发,只在其他标签页触发
常见面试问题
Q1: 有哪些方式实现多标签页通信?
答案:
5 种主要方式:BroadcastChannel(推荐,API 简洁)、localStorage storage 事件、SharedWorker、Service Worker postMessage、window.postMessage(适合跨域 iframe)。优先选 BroadcastChannel。
Q2: 用户在一个标签页登出,如何通知其他标签页?
答案:
// 登出时广播
function logout() {
clearSession();
new BroadcastChannel('auth').postMessage({ type: 'LOGOUT' });
redirectToLogin();
}
// 其他标签页监听
new BroadcastChannel('auth').onmessage = (e) => {
if (e.data.type === 'LOGOUT') {
clearSession();
redirectToLogin();
}
};