适用人群:前端开发者
难度:中等
预计学习时间:8-12小时
核心性能指标(Core Web Vitals)
| 指标 | 全称 | 目标值 | 说明 |
|---|
| LCP | Largest Contentful Paint | < 2.5s | 最大内容渲染时间 |
| FID | First Input Delay | < 100ms | 首次输入延迟 |
| CLS | Cumulative Layout Shift | < 0.1 | 累计布局偏移 |
| INP | Interaction to Next Paint | < 200ms | 交互响应时间 |
| TTFB | Time to First Byte | < 800ms | 首字节时间 |
| FCP | First Contentful Paint | < 1.8s | 首次内容渲染 |
优化策略清单
1. 资源优化
# 图片优化
# 使用WebP/AVIF格式
<picture>
<source srcset="image.avif" type="image/avif">
<source srcset="image.webp" type="image/webp">
<img src="image.jpg" alt="..." loading="lazy" decoding="async">
</picture>
# Next.js图片优化
import Image from 'next/image'
<Image src="/photo.jpg" width={800} height={600} alt="..." priority />
# 代码分割
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
loading: () => <p>Loading...</p>,
ssr: false
})
# Tree Shaking
# 确保使用ESM导入
import { debounce } from 'lodash-es' // 好
import _ from 'lodash' // 坏(整个lodash)
2. 网络优化
# Nginx缓存配置
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# 开启Gzip/Brotli压缩
gzip on;
gzip_types text/plain text/css application/json application/javascript;
gzip_min_length 1000;
# HTTP/2
listen 443 ssl http2;
# 预加载关键资源
<link rel="preload" href="/fonts/main.woff2" as="font" crossorigin>
<link rel="preconnect" href="https://api.example.com">
3. 渲染优化
// React性能优化
import { memo, useMemo, useCallback } from 'react'
// memo避免不必要的重渲染
const ExpensiveList = memo(function ExpensiveList({ items, onSelect }) {
return items.map(item => (
<div key={item.id} onClick={() => onSelect(item.id)}>
{item.name}
</div>
))
})
// useMemo缓存计算结果
function FilteredList({ items, query }) {
const filtered = useMemo(
() => items.filter(item => item.name.includes(query)),
[items, query]
)
return <ExpensiveList items={filtered} />
}
// useCallback缓存函数引用
function Parent() {
const [selected, setSelected] = useState(null)
const handleSelect = useCallback((id) => setSelected(id), [])
return <ExpensiveList items={items} onSelect={handleSelect} />
}
// 虚拟列表(大量数据)
import { useVirtualizer } from '@tanstack/react-virtual'
function VirtualList({ items }) {
const parentRef = useRef(null)
const virtualizer = useVirtualizer({
count: items.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 50
})
return (
<div ref={parentRef} style={{ height: '400px', overflow: 'auto' }}>
<div style={{ height: virtualizer.getTotalSize() }}>
{virtualizer.getVirtualItems().map(vItem => (
<div key={vItem.key} style={{
position: 'absolute',
top: vItem.start,
height: vItem.size,
width: '100%'
}}>
{items[vItem.index].name}
</div>
))}
</div>
</div>
)
}
4. CSS优化
/* 避免昂贵的选择器 */
/* 坏 */
div > ul > li > a > span { }
/* 好 */
.nav-link-text { }
/* 使用contain优化重排 */
.card {
contain: layout style paint;
}
/* 使用content-visibility优化屏幕外元素 */
.below-fold {
content-visibility: auto;
contain-intrinsic-size: 0 500px;
}
/* 减少重绘 */
.animated-element {
will-change: transform;
transform: translateZ(0); /* 创建合成层 */
}
性能检测工具
| 工具 | 用途 |
|---|
| Lighthouse | 综合性能评估 |
| PageSpeed Insights | 在线性能分析 |
| Chrome DevTools Performance | 运行时性能分析 |
| WebPageTest | 多地点测试 |
| bundlephobia | 包体积检查 |
| webpack-bundle-analyzer | 打包分析 |
检查清单
□ 图片使用WebP/AVIF格式
□ 图片懒加载
□ 关键CSS内联
□ JS代码分割
□ 字体子集化
□ 开启Gzip/Brotli压缩
□ 使用CDN
□ 设置合理的缓存策略
□ 减少第三方脚本
□ 使用Intersection Observer
□ 避免布局偏移
□ 服务端渲染/静态生成