页面性能优化不是简单的“压缩一下资源”,而是一套从度量→定位→治理→验收的体系化问题。本文结合实际落地经验,从度量指标、资源体积、网络请求、渲染路径、用户感知与工程化保障几个维度,梳理一条可执行的优化路径。

一、先谈“怎么量”——关键指标

  • Core Web Vitals
    • LCP(Largest Contentful Paint):最大内容绘制时间,衡量首屏主要内容何时可见。
    • INP(Interaction to Next Paint):交互到下一帧的时延,替代 FID 评估交互响应性。
    • CLS(Cumulative Layout Shift):累积布局偏移,衡量页面稳定性。
  • 其他常用指标:TTFB、FCP、TTI、TBT、FP/FMP、JS long task 数量等。

建议:本地用 Lighthouse 建基线,线上用 RUM(真实用户监控)采样埋点,按设备/网络分层观察。

二、资源体积优化(越少越好)

1. JavaScript:减少、拆分、可缓存

  • Tree Shaking / Dead Code Elimination:确保使用 ESM、移除无用导出。
  • Code Splitting:按路由/功能动态加载,降低首屏负担。
1
2
// 路由级按需加载
import('~/pages/settings').then(({ render }) => render());
  • 第三方依赖瘦身
    • 替换大库(如 moment → dayjs/luxon)。
    • 只引入子模块(lodash-es 按需)。
    • 开启 bundler 的现代产物(module/exports 字段、esm 优先)。

2. 压缩与传输编码

  • JS/CSS 开启代码压缩(Terser/CSSNano)。
  • 服务端(或 CDN)开启 Brotli 优先,Gzip 兜底。
1
2
3
4
5
6
gzip on;
gzip_types application/javascript text/css application/json image/svg+xml;
gzip_min_length 1024;

# Brotli(示例需安装 brotli 模块/CDN 支持)
# brotli on; brotli_types application/javascript text/css application/json image/svg+xml;

3. 图片与媒体

  • 格式选型:优先 WebP/AVIF,按兼容性回退。
  • 响应式与懒加载srcset/sizes + loading="lazy" + 显式 width/height 防 CLS。
1
2
3
4
5
6
7
8
9
<img
src="/img/hero.avif"
srcset="/img/hero-640.avif 640w, /img/hero-1280.avif 1280w"
sizes="(max-width: 768px) 100vw, 768px"
loading="lazy"
fetchpriority="high"
width="1280" height="720"
alt="hero"
/>
  • 占位/渐进:LQIP/BlurHash;视频首帧海报 poster。

4. CSS 与字体

  • Critical CSS:首屏关键样式内联/预加载;非关键样式延后应用。
1
2
<link rel="preload" as="style" href="/css/critical.css" />
<link rel="stylesheet" href="/css/index.css" media="print" onload="this.media='all'" />
  • Purge/Unused CSS:PurgeCSS/Tailwind JIT 等移除未使用选择器。
  • 字体:子集化 + font-display: swap + 预加载。
1
2
3
4
5
@font-face {
font-family: 'InterSubset';
src: url('/fonts/inter-subset.woff2') format('woff2');
font-display: swap;
}
1
<link rel="preload" as="font" href="/fonts/inter-subset.woff2" type="font/woff2" crossorigin>

三、网络请求优化(更快拿到、更少往返)

1. 协议与拓扑

  • HTTP/2/3 多路复用、头部压缩;尽量走 CDN(就近、缓存、压缩、TLS 优化)。
  • 合理的域名拆分,控制并发与连接复用。

2. 缓存策略

  • 静态资源指纹化 + Cache-Control: public, max-age=31536000, immutable
  • 非指纹接口配合 ETag/Last-Modified,短缓存 + 协商。
1
2
Cache-Control: public, max-age=31536000, immutable
ETag: "68f4-5f1a..."

3. 预连接与预加载

1
2
3
4
<link rel="dns-prefetch" href="//cdn.example.com">
<link rel="preconnect" href="https://cdn.example.com" crossorigin>
<link rel="preload" as="script" href="/js/main.js">
<link rel="prefetch" href="/js/route-settings.chunk.js">

4. 阻塞外链与脚本

  • defer 优先、慎用 async(有依赖顺序时)。
1
<script src="/js/main.js" defer></script>
  • 延迟/条件加载三方脚本(埋点、广告、A/B 等),必要时沙箱隔离。
  • Service Worker:离线缓存、预缓存关键路径,回源兜底。

四、渲染与主线程优化(更快可见、更快可交互)

1. 关键渲染路径(CRP)

  • 减少首屏 JS 执行量与 CSS 阻塞;SSR/SSG 提升首屏可见性;Hydration 分片或延后。
  • 精简首屏 DOM 复杂度,避免大列表一次性渲染(使用虚拟列表/分页)。

2. 主线程“长任务”治理

  • 将 >50ms 的长任务拆分到多个微任务/宏任务,或丢给 Web Worker
1
2
3
// 计算密集任务放 Worker
const worker = new Worker('/worker.js');
worker.postMessage({ type: 'calc', payload: bigData });
  • 动画使用 transform/opactiy,避免触发布局;使用 will-change 谨慎。
  • 事件节流/防抖,减少同步布局抖动(Layout Thrashing)。

3. 优先级与调度

  • 使用 requestIdleCallback 在空闲时做非关键工作;采用现代框架的并发特性/调度器。
  • 网络/渲染优先级:fetchpriority="high" 用于首图,priority hints 配合资源管理。

五、用户感知优化(看起来更快)

  • Skeleton/占位:首屏骨架、图片模糊占位,避免“白屏恐惧”。
  • 渐进展示:先上关键信息,再补充增强;列表先展示可见区域。
  • 交互回馈:按钮点击即刻反馈(禁用态/Loading),避免用户重复操作。
  • 错误/重试策略:弱网下的容错与降级,提供离线提示。
1
2
<!-- 示例:图片首帧优先 -->
<img src="/img/hero.jpg" fetchpriority="high" alt="hero" />

六、工程化与持续保障

  • 性能预算(Performance Budget):为 JS/CSS/图片设定体积与指标预算,超标即失败。
  • 分析工具:webpack-bundle-analyzer、Source Map 体积审计;依赖许可证与重复库检测。
  • CI 守门:Lighthouse CI/Calibre/SpeedCurve 接入流水线;PR 侧边栏展示变化。
  • RUM 监控:上报 LCP/CLS/INP、资源耗时、长任务、错误栈;按端/网络维度聚合。
  • 实验治理:灰度/AB 测试,评估改动对指标的真实影响。

七、常见坑与对策

  • 过多三方脚本 → 延迟/条件加载,或使用代理与沙箱;定期体检下线。
  • 大而全 polyfill → 基于 UA/feature 的差异化注入(polyfill.io/self-host)。
  • 单包过大 → 路由/组件分包、公共依赖拆分、动态导入。
  • Reflow 频繁 → 批量读写 DOM(FastDom)、动画走合成层。
  • 图片失衡 → 统一中台(裁剪/压缩/格式自动),规范宽高与密度。

八、落地清单(Checklist)

  • 已建立 CWV 与性能预算基线,并接入线上 RUM。
  • 首屏 JS < 170KB(gz/br 后)、首屏 CSS < 30KB;路由级分包。
  • 图片 WebP/AVIF + 懒加载 + 宽高/占位;字体子集化 + preload。
  • 静态资源带指纹且长缓存;接口协商缓存;预连接/预加载关键资源。
  • 关键渲染路径可控:Critical CSS、defer 脚本、SSR/SSG 可选。
  • 长任务监控 < 50ms;Worker/调度器落地;虚拟列表替换大渲染。

结语

性能优化是长期工程,遵循“度量驱动”的闭环——先测量、再优化、再验证,并通过工程化手段持续守住基线。把资源做小、请求提效、渲染加速、感知做足,最终会体现在稳定优秀的用户体验与业务转化上。

Happy Coding!