Service Worker缓存脚本加载旧数据:除提示刷新外的解决方案咨询
解决异步加载JSON时缓存不匹配导致的404问题
这个场景我太熟悉了——打包后的资源带哈希后缀,旧缓存的脚本还在找旧文件名的JSON,结果触发404。除了弹出提示让用户刷新,还有几个更平滑的方案,能减少用户感知甚至完全无感知:
1. 版本化资源清单(Manifest)
构建时生成一个包含所有资源哈希路径的manifest.json,应用启动先拉取这个清单,对比本地缓存的版本,确认资源路径后再加载JSON。这样不管脚本是不是旧的,都能拿到最新的资源路径。
示例代码:
// 应用初始化时先校验资源清单 async function initApp() { try { const remoteManifest = await fetch('/manifest.json').then(res => res.json()); const localManifest = JSON.parse(localStorage.getItem('app-resource-manifest') || '{}'); // 如果清单不一致,更新本地缓存的路径映射 if (remoteManifest['data.json'] !== localManifest['data.json']) { localStorage.setItem('app-resource-manifest', JSON.stringify(remoteManifest)); } // 用清单里的最新路径加载JSON const data = await import(`./assets/${remoteManifest['data.json']}.json`); renderApp(data.default); } catch (err) { // 兜底:加载默认的JSON或者提示用户 console.error('加载资源失败', err); } } initApp();
注意:manifest.json本身要设置不缓存(服务器响应头Cache-Control: no-cache),不然用户会一直拿到旧清单。
2. 服务端Fallback机制
在服务器配置里,给JSON资源加一个兜底规则:当请求的旧哈希文件不存在时,直接返回最新版本的JSON。这样旧脚本即使请求了不存在的文件,也能拿到有效数据,用户完全无感知,等下次自然刷新就会加载新脚本了。
以Nginx为例,配置规则:
location ~* ^/assets/.*\.json$ { # 先尝试请求原路径,不存在就返回最新的JSON文件 try_files $uri /assets/latest-data.json; }
构建时记得把最新的JSON文件同时复制一份为latest-data.json,或者用构建工具自动同步这个文件。
3. 后台预加载+无缝切换
当检测到版本更新时,不立即打扰用户,而是在后台悄悄加载新的脚本和资源,等用户进行下一次主动操作(比如切换页面、点击按钮)时,无缝切换到新版本。
示例思路:
let hasNewVersion = false; let newAppEntry = null; let remoteVersion = ''; // 检测版本更新 async function checkForUpdate() { const currentVersion = localStorage.getItem('app-version') || 'initial'; remoteVersion = await fetch('/version.txt').then(res => res.text().trim()); if (remoteVersion !== currentVersion) { hasNewVersion = true; // 后台加载新的入口脚本 const script = document.createElement('script'); script.src = `/app.${remoteVersion}.js`; script.onload = () => { // 新脚本加载完成后,暴露初始化方法 newAppEntry = window.initNewApp; // 可以给个轻量提示,比如右上角小徽章“有更新,点击生效” showUpdateBadge(); }; document.body.appendChild(script); } } // 用户操作时触发切换 document.addEventListener('click', (e) => { if (hasNewVersion && newAppEntry) { // 销毁当前旧应用实例 destroyCurrentApp(); // 初始化新应用 newAppEntry(); // 更新本地版本标记 localStorage.setItem('app-version', remoteVersion); hasNewVersion = false; hideUpdateBadge(); } }); // 页面加载时启动版本检测 checkForUpdate();
4. Service Worker精准缓存控制
用Service Worker拦截所有资源请求,当请求的JSON文件404时,自动 fallback 到最新版本,或者提前缓存新版本资源。
Service Worker示例代码:
self.addEventListener('fetch', (event) => { const requestUrl = new URL(event.request.url); // 只处理JSON资源请求 if (requestUrl.pathname.endsWith('.json')) { event.respondWith( fetch(event.request) .catch(async () => { // 请求失败,返回最新的JSON资源 return await fetch('/assets/latest-data.json'); }) ); } });
这种方案适合PWA应用,能做到完全无感知的资源容错。
内容的提问来源于stack exchange,提问作者Timo Jokinen
相关产品推荐
相关产品推荐

