前端性能优化
代码分割
// 动态导入 (React)
const HeavyChart = React.lazy(() => import('./HeavyChart'));
function App() {
return (
<React.Suspense fallback={<Spinner />}>
{showChart && <HeavyChart />}
</React.Suspense>
);
}
// 基于路由的分割 (React Router)
const Dashboard = React.lazy(() => import('./pages/Dashboard'));
// Vite 动态导入
const { default: module } = await import('./heavy-module.js');
渲染性能
// 避免布局抖动——批量读写 DOM
// 不好的做法:交替读写
el1.style.width = el2.offsetWidth + 'px'; // 触发重排
el3.style.height = el4.offsetHeight + 'px'; // 再次触发
// 好的做法:先批量读,再批量写
const w = el2.offsetWidth; // 读
const h = el4.offsetHeight; // 读
el1.style.width = w + 'px'; // 写
el3.style.height = h + 'px'; // 写
// 动画使用 requestAnimationFrame
function animate() {
element.style.transform = `translateX(${pos}px)`;
pos += 1;
requestAnimationFrame(animate);
}
// 使用 CSS transform/opacity(GPU 合成)
// 好: transform, opacity, filter
// 差: top, left, width, height(触发布局)
打包优化
// Vite 手动分块
export default {
build: {
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
charts: ['recharts'],
utils: ['lodash-es', 'date-fns']
}
}
}
}
}
// 按需导入
import { debounce } from 'lodash-es'; // 支持 tree-shaking
// 不要: import _ from 'lodash';
性能指标参考
| 指标 | 目标值 | 工具 |
|---|---|---|
| LCP | < 2.5s | Lighthouse、CrUX |
| INP | < 200ms | Lighthouse、CrUX |
| CLS | < 0.1 | Lighthouse、CrUX |
| TTFB | < 200ms | WebPageTest |
| JS 包大小 | < 170KB(gzip) | Bundlesize |
| 页面总体积 | < 1MB | Chrome DevTools、GTmetrix |