当用户打开多个相同网站的标签页时,每个标签页都会独立运行JavaScript代码,可能导致重复的API请求、重复操作或状态不一致问题。
// 在所有标签页中
const channel = new BroadcastChannel('app_channel');
// 发送请求前检查其他标签页是否已发送
channel.postMessage({type: 'request_check', endpoint: '/api/data'});
// 监听其他标签页的消息
channel.onmessage = (e) => {
if (e.data.type === 'request_check' && e.data.endpoint === '/api/data') {
// 可以响应表示自己正在处理
channel.postMessage({type: 'request_in_progress', endpoint: '/api/data'});
}
if (e.data.type === 'data_updated') {
// 使用其他标签页获取的数据
updateUI(e.data.payload);
}
};
// 获取数据后通知其他标签页
fetch('/api/data').then(res => res.json()).then(data => {
channel.postMessage({type: 'data_updated', payload: data});
});
// 主标签页
localStorage.setItem('request_lock', Date.now());
fetch('/api/data').then(res => res.json()).then(data => {
localStorage.setItem('api_data', JSON.stringify(data));
localStorage.removeItem('request_lock');
});
// 所有标签页
window.addEventListener('storage', (event) => {
if (event.key === 'api_data') {
const data = JSON.parse(event.newValue);
updateUI(data);
}
if (event.key === 'request_lock') {
// 知道其他标签页正在处理请求
}
});
// 在Service Worker中
self.addEventListener('fetch', (event) => {
if (event.request.url.includes('/api/')) {
event.respondWith(
caches.open('api-cache').then((cache) => {
return cache.match(event.request).then((response) => {
return response || fetch(event.request).then((response) => {
cache.put(event.request, response.clone());
return response;
});
});
})
);
}
});
// 创建共享Worker
const worker = new SharedWorker('shared-worker.js');
// shared-worker.js
let requestInProgress = false;
self.onconnect = function(e) {
const port = e.ports[0];
port.onmessage = function(e) {
if (e.data.type === 'fetch') {
if (!requestInProgress) {
requestInProgress = true;
fetch(e.data.url).then(res => res.json()).then(data => {
requestInProgress = false;
port.postMessage({type: 'response', data});
});
}
}
};
};
根据场景选择方案:
请求去重:
错误处理:
性能优化:
这些方案可以单独使用或组合使用,具体取决于您的应用架构和需求复杂度。