
单页应用的性能瓶颈一般不是“页面慢”,而是首屏 JS 体积过大、主线程被长任务占满、路由切换时重复下载和重排。LCP、INP、CLS 这三个核心网页指标可以更好的体现真实的用户体验:LCP 表示主要内容什么时候出现,INP 表示操作是否跟手,CLS 表示画面是否稳定。
侧边栏优先采集字段数据而不是只看Lighthouse实验室分数,用web-vitals来接入真实的用户监控,按照路由、设备和交互方式把LCP/INP/CLS分开来看,重点关注75分位的表现。对于单页应用来说还需要注意软导航之后第二次渲染的情况,防止出现“首页快但是进详情页慢”的现象。
LCP 优化从“少执行、早发现”开始:公开页面尽量 SSR/SSG 直接输出,LCP 图片不使用懒加载和预连接,并且设置 fetchpriority="high",首屏重要的 CSS 内联,非重要 JS 延迟加载。INP 优化的重点是拆分长任务——使用 useTransition、防抖节流、Web Worker 来把点击和输入操作从主线程中解放出来,第三方脚本放在后面加载。CLS 则通过预留尺寸来实现:给图片设置宽高或者 aspect-ratio,广告位、弹窗、异步模块容器固定高度,动画只使用 transform/opacity。
代码分割和懒加载是单页应用的基本工具。在路由级别上,使用动态 import() 来拆分页面 chunk,在 React 中用 React.lazy + Suspense,在 Vue 中用 defineAsyncComponent;对于重型图表、编辑器以及埋点 SDK 等组件则采用组件级别的懒加载方式。打包器会把第三方库和公共依赖单独打包出来,配合 Brotli 压缩和长缓存一起使用。懒加载并不是越细越好——过度细分会产生请求瀑布效应,按照“首屏必须+路由粒度+使用概率”的原则进行分块更加合理一些。对于高概率的下一次跳转路由,在空闲的时候可以进行 prefetch 或者利用 Speculation Rules 来提前渲染。
性能优化要融入到发布流程中:在CI里运行Lighthouse性能预算、在生产环境中不断收集字段数据、每次发布都和同口径75分位做比较。首先要减小JS体积和长任务,然后修正布局偏移问题,最后调整字体以及缓存设置来防止出现“刷满分但是真实用户仍然卡顿”的情况。
SPA 性能优化的核心在于用真实的字段数据来找到瓶颈所在,然后再通过 SSR/SSG、代码分割、懒加载和长任务拆分组合等方式来解决它。衡量标准并不是实验室里的高分,而是在各种各样的设备上以及网络状况不好的情况下首屏加载速度快、页面切换流畅、没有闪烁的现象。