前端性能优化:一些实战经验

性能优化是个大话题,网上文章很多,但有些方案看着很美好,实际效果一般。这里记录一些我用过、确实有效的手段。

打包优化

这个是投入产出比最高的。

代码分割

// 动态 import,自动分包
const Module = await import('./heavy-module');

// React
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));

我们有个后台系统,把图表库抽出去单独加载,首屏 bundle 从 2MB 降到了 400KB。

第三方库优化

有些库支持按需引入:

// 不好
import _ from 'lodash';

// 好
import debounce from 'lodash/debounce';

或者用 lodash-es + Tree Shaking。

图片优化

图片往往是页面最大的资源。

  1. WebP 格式,比 JPEG 小 25%-35%
  2. 响应式图片 <picture> + srcset
  3. 懒加载 loading="lazy"
<picture>
  <source srcset="image.webp" type="image/webp">
  <img src="image.jpg" loading="lazy" alt="...">
</picture>

还有个容易被忽略的点:不要用原图。产品上传的图动不动好几 MB,一定要在服务端处理一下。

渲染优化

虚拟列表

长列表必备。react-window、vue-virtual-scroller 都挺好用。

防抖节流

搜索输入、滚动监听这些高频事件,一定要处理。

const handleSearch = debounce((value) => {
  fetchResults(value);
}, 300);

React 的 memo

别滥用,先分析是不是真的有性能问题。很多时候渲染本身就很快,加了 memo 反而多了一次比较。

缓存策略

Service Worker + Cache API 可以做离线缓存,但配置起来有点麻烦。如果只是想缓存静态资源,HTTP 缓存头就够了。

# 静态资源
location /static {
  expires 1y;
  add_header Cache-Control "public, immutable";
}

# HTML 不缓存
location / {
  add_header Cache-Control "no-cache";
}

监控

优化之前先有数据,否则不知道优化效果。我们用的是自定义的性能采集:

const timing = performance.getEntriesByType('navigation')[0];
const metrics = {
  DNS: timing.domainLookupEnd - timing.domainLookupStart,
  TCP: timing.connectEnd - timing.connectStart,
  TTFB: timing.responseStart - timing.requestStart,
  // ...
};

然后上报到监控平台。

最后

性能优化没有银弹,关键是先找到瓶颈在哪。用 Chrome DevTools 的 Performance 面板看一眼,比盲目优化强多了。

还有一点:别过早优化。先把功能做出来,有性能问题了再处理。大部分项目的性能瓶颈其实就一两个地方,解决了就够用了。