前端性能优化:一些实战经验
性能优化是个大话题,网上文章很多,但有些方案看着很美好,实际效果一般。这里记录一些我用过、确实有效的手段。
打包优化
这个是投入产出比最高的。
代码分割
// 动态 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。
图片优化
图片往往是页面最大的资源。
- WebP 格式,比 JPEG 小 25%-35%
- 响应式图片
<picture>+srcset - 懒加载
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 面板看一眼,比盲目优化强多了。
还有一点:别过早优化。先把功能做出来,有性能问题了再处理。大部分项目的性能瓶颈其实就一两个地方,解决了就够用了。