5月31日 20:28

PWA 缓存策略怎么选?不同资源该用哪种缓存方式?

PWA 缓存策略不是把资源一股脑塞进 Cache Storage。真正要做的是按资源的变化频率、实时性要求和离线价值分开处理:静态资源优先速度,接口数据优先新鲜度,关键页面要能降级,支付、库存、权限这类请求通常不要缓存。选错策略的后果很直接,用户可能看到旧价格、旧头像,或者离线时连一页友好的提示都没有。

常见缓存策略怎么选

Cache First 适合版本号稳定的 JS、CSS、字体、Logo、插图。它先查缓存,命中就返回,没命中再请求网络。好处是快,离线也能用;边界是资源必须有版本管理,否则你发布了新包,用户还可能拿到旧文件。

javascript
self.addEventListener('fetch', event => { const url = new URL(event.request.url); if (url.pathname.startsWith('/assets/')) { event.respondWith( caches.match(event.request).then(hit => hit || fetch(event.request)) ); } });

Network First 适合 HTML 文档、用户资料、订单列表、文章详情等需要尽量新的内容。它先请求网络,失败时再回退到缓存。这个策略的取舍是首屏会受网络影响,所以最好配合超时控制,不要让用户在弱网下等到浏览器自己放弃。

Stale While Revalidate 适合头像、配置、推荐列表、非强一致的内容。它先返回缓存,让页面马上有东西显示,同时后台请求新数据并更新缓存。踩坑点是用户短时间内可能看到旧内容,因此不要用在支付状态、库存数量、风控结果这种需要准确性的场景。

Network Only 用在登录、支付、实时协作、埋点上报等请求。它不走缓存,保证语义清楚。Cache Only 则适合离线页、预缓存的壳资源,前提是安装阶段已经把这些资源放进缓存。

推荐的混合配置

实际项目里一般不会只用一种策略。常见做法是静态资源 Cache First,HTML Network First,非关键接口 Stale While Revalidate,敏感接口 Network Only,离线页 Cache Only。缓存名要带版本号,激活新 Service Worker 时清理旧缓存,否则用户设备上会越积越多。

javascript
const CACHE = 'pwa-cache-v3'; const PRECACHE = ['/', '/offline.html', '/assets/app.css']; self.addEventListener('install', event => { event.waitUntil(caches.open(CACHE).then(cache => cache.addAll(PRECACHE))); }); self.addEventListener('activate', event => { event.waitUntil( caches.keys().then(keys => Promise.all(keys.filter(k => k !== CACHE).map(k => caches.delete(k))) ) ); });

上线前还要检查什么

缓存策略上线前要单独测三种状态:首次访问、已有旧缓存后访问、断网后访问。很多问题只在第二种状态出现,例如 HTML 已更新但旧 JS 还在运行,页面会报接口字段不存在。接口响应如果要进入缓存,最好先检查 response.ok,不要把 500 错误页也缓存进去。跨域资源还要注意 opaque response,它看不到状态码,缓存前要确认这个资源真的值得长期保存。

追问

Cache First 和 Network First 最大区别是什么?

Cache First 把速度放在第一位,Network First 把内容新鲜度放在第一位。静态资源通常不常变,用 Cache First 能明显减少加载时间。动态接口如果也用 Cache First,最容易出现用户看到旧数据的问题。实际取舍要看“旧一点是否可接受”,而不是看哪种策略更高级。

Stale While Revalidate 适合所有接口吗?

不适合,它适合允许短暂过期的数据,比如推荐列表、用户头像、公共配置。它的边界是第一次没有缓存时仍然要等网络,之后才会体现“秒开”。踩坑最多的是把它用在订单状态或余额上,用户看到旧结果会产生信任问题。强一致接口宁可慢一点,也不要返回旧值。

缓存版本号应该怎么设计?

缓存名最好跟构建版本或资源清单版本绑定,例如 pwa-cache-v20260531。如果资源 URL 已经带 hash,可以让静态资源长期缓存,发布时自然换 URL。不要每次刷新都换缓存名,那会让缓存失去意义,也会增加清理压力。版本升级时重点清旧缓存,但不要误删当前页面还在使用的资源。

离线页面应该缓存哪些内容?

至少缓存一个 /offline.html、基础样式和必要图标,让断网时有明确反馈。不要试图把整个站点都预缓存,移动端存储空间和安装速度都会受影响。边界是“离线能完成核心阅读或提示”即可,不必让所有功能离线可用。踩坑点是离线页引用了未缓存的 CSS 或图片,结果断网时页面仍然是坏的。

如何避免缓存把线上问题放大?

发布前要在 DevTools 的 Application 面板测试更新流程,确认旧缓存会被清理。关键资源建议使用带 hash 的文件名,接口缓存要设置白名单,不要按域名全部缓存。遇到线上故障时,可以通过提升缓存版本和返回 no-store 响应来切断旧内容。缓存能提升体验,也会让错误保留更久,所以策略越激进,回滚方案越要提前准备。

标签:PWA