PWA 离线功能怎么做才能避免缓存旧页面?
PWA 离线功能的核心不是“断网也能打开页面”,而是让用户在弱网、断网、恢复联网之间不丢数据、不看错数据。Service Worker 拦截请求,Cache API 存静态资源,IndexedDB 存业务数据。难点在取舍:哪些内容能离线读,哪些必须实时请求,哪些失败后要明确提示。
追问
离线功能最小可用版本应该包含什么?
最小版本包括 Service Worker 注册、应用外壳预缓存、离线兜底页和网络状态提示。应用外壳指 HTML、核心 CSS、入口 JS、图标和 offline.html,不是全站所有资源。取舍上,预缓存越多首次安装越慢,也更容易导致 install 失败。建议先保证核心路径能打开,再逐步给文章、表单草稿加离线能力。
jsconst CACHE = 'app-shell-v1'; self.addEventListener('install', e => { e.waitUntil(caches.open(CACHE).then(c => c.addAll([ '/', '/offline.html', '/app.css', '/app.js' ]))); });
fetch 缓存策略应该怎么选?
静态资源适合 cache first,因为文件名通常带 hash,命中缓存速度最快。HTML 更适合 network first,失败后再返回缓存或 offline.html,避免用户长期停留在旧页面。接口数据要按业务分级:文章详情可 stale-while-revalidate,余额、权限、库存不要离线伪造。踩坑是用一个通用 caches.match 处理所有请求,结果 POST、鉴权接口和跨域资源都被误缓存。
jsself.addEventListener('fetch', e => { if (e.request.method !== 'GET') return; if (e.request.mode === 'navigate') { e.respondWith(fetch(e.request).catch(() => caches.match('/offline.html'))); } });
离线写入数据怎么避免丢失?
离线提交不要直接失败,可以先把用户输入保存到 IndexedDB,并标记 pending 状态。恢复联网后再用 Background Sync 或前台重试队列同步。边界是 Background Sync 兼容性并不完美,不能把它当成唯一兜底,页面重新打开时也要主动检查待同步数据。服务端还要支持幂等键,否则弱网重试可能造成重复订单或重复扣费。
缓存更新最容易踩什么坑?
最常见的是新 Service Worker 已安装但旧页面仍由旧版本控制,用户刷新几次仍看到旧资源。skipWaiting 和 clients.claim 可以加快接管,但也可能让正在使用的页面突然加载到新旧混合资源。取舍上,内容型站点可以更积极更新,复杂后台系统最好提示用户刷新。每次发布都应改变资源 hash,并在 activate 阶段清理旧缓存。
怎么测试 PWA 离线能力是否可靠?
Chrome DevTools 的 Offline 模式只能覆盖一部分情况,还要测试慢 3G、接口超时、DNS 失败和缓存被清理。移动端尤其要测首次访问、二次访问、更新后访问和久未打开后的访问。踩坑是本地 localhost 下表现正常,线上 HTTPS、CDN 缓存和 Service Worker scope 不一致导致注册失败。验收时看四项:断网能否打开、离线页是否出现、草稿是否保留、恢复网络后是否同步。