5月31日 17:42

PWA 性能优化应该先改缓存还是先改资源加载?

PWA 性能优化不要一上来就把所有资源塞进缓存。更稳的做法是先看瓶颈:首屏慢,多半是 JavaScript、CSS、字体和图片阻塞;二次访问慢,再重点看 Service Worker 缓存;交互卡顿,则要拆主线程任务。PWA 的优势是“像 App 一样快”,但缓存策略写错,用户看到的可能是旧页面,甚至是旧接口数据。

追问

首屏性能应该先优化哪些资源?

首屏优先处理 HTML、关键 CSS、入口 JS、首屏图片和字体,因为它们直接影响 FCP、LCP 和 INP。取舍上,不建议把所有 CSS 都内联,内联过多会让 HTML 变胖。比较稳的边界是只内联首屏必需样式,其他样式用 preload 或按路由拆包。图片要用 WebP/AVIF,并明确 width 和 height,避免 LCP 图片加载晚或造成布局抖动。

html
<link rel="preload" href="/hero.webp" as="image"> <img src="/hero.webp" width="720" height="360" fetchpriority="high" alt="PWA 首页">

Service Worker 缓存是不是越多越好?

不是,缓存越多,更新和存储压力越大,移动端还可能被浏览器清理。静态资源适合 cache first,但 HTML 和接口更适合 network first 或 stale-while-revalidate。踩坑最多的是把 /api/user 这类强实时接口放进长期缓存,用户退出登录后还能看到旧数据。建议给缓存分层命名,例如 static-v3、runtime-v3,并在 activate 阶段清掉旧版本。

js
self.addEventListener('fetch', e => { const url = new URL(e.request.url); if (url.pathname.startsWith('/assets/')) e.respondWith(cacheFirst(e.request)); else if (url.pathname.startsWith('/api/')) e.respondWith(networkFirst(e.request)); });

代码分割和预缓存怎么取舍?

代码分割能降低首屏包体,但切得太碎会增加请求数,弱网下反而更慢。预缓存适合 shell、核心路由和稳定静态资源,不适合频繁变化的业务 chunk。一个实用边界是:首屏必需的 chunk 预缓存,低频页面按需加载,高频但非首屏的页面用 prefetch。上线后要看真实用户数据,而不是只看本地 Lighthouse。

图片、字体和第三方脚本有哪些常见坑?

图片不要只做 lazy loading,首屏大图懒加载会直接拖慢 LCP。字体建议使用 font-display: swap,并只加载实际用到的字重。第三方脚本要能延后就延后,统计、客服、广告脚本经常是 INP 变差的主因。边界是支付、登录风控这类关键脚本不能随便 defer,需要按业务路径单独评估。

怎么判断优化真的有效?

不要只看一次 Lighthouse 分数,至少要同时看实验室数据和线上 Web Vitals。LCP、CLS、INP、TTFB 能覆盖大部分 PWA 体验问题,缓存命中率和 Service Worker 更新失败率也要一起看。踩坑是只在强网桌面环境测试,结果移动端 4G 下 JS 执行和图片解码完全不同。建议把 web-vitals 上报到日志系统,按路由、设备和网络类型分组看趋势。

标签:PWA