页面加载速度直接影响用户留存率。研究表明,页面加载时间每增加 1 秒,转化率下降 7%。本文记录了一次完整的性能优化过程,将首屏加载时间从 3 秒优化到 800 毫秒。

现状分析

优化之前,我们用 Lighthouse 对页面进行了全面的性能审计,发现几个主要问题:

  • JavaScript Bundle 体积过大(1.2MB gzipped)
  • 首屏渲染被大量未使用的 CSS 阻塞
  • 图片未做懒加载,首屏请求了 30+ 张图片
  • 第三方脚本(埋点、客服)阻塞了主线程

优化策略一:资源加载

代码分割(Code Splitting)

将路由级别的代码进行动态导入,首屏只加载必要的代码。配合 Webpack 的 Magic Comments 设置预加载策略:

const Dashboard = React.lazy(() => import(
  /* webpackChunkName: "dashboard" */
  /* webpackPrefetch: true */
  './pages/Dashboard'
));

这一项优化将首屏 JS 体积从 1.2MB 降低到 320KB。

图片懒加载

使用 Intersection Observer API 实现图片懒加载,首屏之外的图片在滚动到可视区域时才开始加载。同时为所有图片生成 WebP 格式,在支持的浏览器中使用更小的体积。

字体优化

使用 font-display: swap 避免字体加载阻塞渲染,同时使用 <link rel="preload"> 提前加载关键字体文件。

优化策略二:渲染优化

Critical CSS 内联

提取首屏关键 CSS 内联到 HTML 的 <head> 中,非关键 CSS 异步加载。这使得浏览器无需等待外部 CSS 文件下载完成即可开始渲染首屏。

减少布局抖动

为所有图片和广告位预留固定尺寸,避免图片加载完成后触发回流。使用 CSS aspect-ratio 属性替代传统的 padding-top hack。

优化策略三:运行时优化

虚拟列表

对于长列表场景,使用虚拟列表只渲染可视区域内的 DOM 节点。这不仅减少了初始渲染时间,还大幅降低了内存占用。

防抖与节流

搜索框输入使用防抖(debounce),滚动事件使用节流(throttle),避免频繁触发昂贵的计算操作。

Web Worker

将数据处理和图表计算等 CPU 密集型任务放到 Web Worker 中执行,避免阻塞主线程导致页面卡顿。

第三方脚本治理

对埋点 SDK、客服组件等第三方脚本进行治理:

  • 非关键脚本使用 deferasync 加载
  • 埋点 SDK 改用 requestIdleCallback 在空闲时初始化
  • 客服组件改为点击时动态加载,而非页面初始化时全量加载

优化成果

经过以上优化,各项核心指标均有显著提升:

  • FCP(首次内容绘制):3.2s → 0.8s
  • LCP(最大内容绘制):4.5s → 1.2s
  • TTI(可交互时间):5.1s → 1.5s
  • Lighthouse Performance 评分:42 → 93

总结

性能优化不是一次性的工作,而是需要持续关注和迭代的过程。建议在 CI/CD 流程中集成 Lighthouse CI,每次发版自动检测性能指标,防止劣化回归。同时,建立性能预算(Performance Budget),为关键指标设定上限,超过时自动阻断发布。