前端性能优化综合
文章目录
- 前言
- 一、Core Web Vitals
- 1.1 三大核心指标
- 1.2 测量方式
- 二、首屏优化
- 2.1 资源加载优化
- 2.2 渲染优化
- 2.3 图片优化
- 三、运行时优化
- 3.1 虚拟列表
- 3.2 防抖与节流
- 3.3 避免不必要的渲染
- 四、网络优化
- 4.1 HTTP 缓存
- 4.2 资源压缩
- 4.3 CDN 加速
- 五、字体优化
- 六、缓存策略
- 七、性能监控
- 八、易混淆点
- 九、思考与练习
- 总结
前言
性能优化是前端开发的核心课题,直接影响用户体验和业务指标。本篇会讲清楚:
- Core Web Vitals(LCP / INP / CLS)
- 首屏优化策略
- 运行时优化
- 网络优化
- 防抖节流的应用
一、Core Web Vitals
1.1 三大核心指标
// 1. LCP(Largest Contentful Paint):最大内容绘制// 衡量加载性能,理想值 ≤ 2.5 秒// 2. INP(Interaction to Next Paint):交互到下次绘制// 衡量交互性能,理想值 ≤ 200 毫秒// 3. CLS(Cumulative Layout Shift):累积布局偏移// 衡量视觉稳定性,理想值 ≤ 0.11.2 测量方式
// 使用 web-vitals 库import{onLCP,onINP,onCLS}from'web-vitals'onLCP(console.log)onINP(console.log)onCLS(console.log)// 使用 Performance APIconstobserver=newPerformanceObserver((list)=>{for(constentryoflist.getEntries()){console.log(entry.name,entry.startTime)}})observer.observe({type:'largest-contentful-paint',buffered:true})二、首屏优化
2.1 资源加载优化
// 1. 代码分割:按路由懒加载constHome=lazy(()=>import('./Home'))constDashboard=lazy(()=>import('./Dashboard'))// 2. 预加载关键资源<link rel="preload"href="/fonts/main.woff2"as="font"crossorigin><link rel="preload"href="/critical.css"as="style">// 3. 预连接第三方源<link rel="preconnect"href="https://api.example.com"><link rel="dns-prefetch"href="https://cdn.example.com">2.2 渲染优化
// 1. SSR / SSG:服务端渲染或静态生成// 首屏 HTML 直接返回,无需等待 JS 下载执行// 2. 骨架屏:减少白屏感知functionApp(){return(<Suspense fallback={<Skeleton/>}><ActualContent/></Suspense>)}// 3. 流式渲染:逐步展示内容// React 18 的 Streaming SSRimport{renderToPipeableStream}from'react-dom/server'2.3 图片优化
// 1. 使用现代格式// WebP:比 JPEG 小 25-35%// AVIF:比 WebP 小 20%// 2. 响应式图片<img srcset="small.jpg 480w, medium.jpg 800w, large.jpg 1200w"sizes="(max-width: 600px) 480px, 800px"src="medium.jpg"loading="lazy"decoding="async">// 3. 图片懒加载<img loading="lazy"src="image.jpg"alt="...">// 4. 渐进式加载// 先加载低质量占位图(LQIP),再替换为高清图<img src="placeholder-blur.jpg"data-src="high-res.jpg">三、运行时优化
3.1 虚拟列表
// 大量列表项使用虚拟列表,只渲染可见区域import{FixedSizeList}from'react-window'functionVirtualList({items}){return(<FixedSizeList height={400}itemCount={items.length}itemSize={50}>{({index,style})=>(<div style={style}>{items[index].name}</div>)}</FixedSizeList>)}// 10000 条数据只渲染约 20 条可见项3.2 防抖与节流
// 防抖:连续触发时只执行最后一次functiondebounce(fn,delay){lettimer=nullreturnfunction(...args){clearTimeout(timer)timer=setTimeout(()=>fn.apply(this,args),delay)}}// 应用场景:搜索框输入、窗口 resizeconsthandleSearch=debounce((keyword)=>{fetchResults(keyword)},300)// 节流:固定间隔内只执行一次functionthrottle(fn,interval){letlastTime=0returnfunction(...args){constnow=Date.now()if(now-lastTime>=interval){lastTime=nowfn.apply(this,args)}}}// 应用场景:滚动事件、鼠标移动consthandleScroll=throttle(()=>{checkVisibility()},100)3.3 避免不必要的渲染
// 1. React.memo:缓存组件constMemoizedChild=React.memo(Child)// 2. useMemo:缓存计算结果constfilteredList=useMemo(()=>items.filter(item=>item.active),[items])// 3. useCallback:缓存函数引用consthandleClick=useCallback(()=>{setCount(prev=>prev+1)},[])// 4. 避免在渲染中创建新对象// ❌ 错误:每次渲染都创建新对象<Child style={{color:'red'}}/>// ✅ 正确:缓存对象conststyle=useMemo(()=>({color:'red'}),[])<Child style={style}/>四、网络优化
4.1 HTTP 缓存
// 强缓存:直接使用缓存,不发请求// Cache-Control: max-age=31536000// 适用于:静态资源(JS、CSS、图片)// 协商缓存:发请求验证是否过期// ETag / Last-Modified// 适用于:HTML、API 响应4.2 资源压缩
// 1. Gzip / Brotli 压缩// Brotli 比 Gzip 小 15-20%// 2. 代码压缩// Terser:压缩 JS// cssnano:压缩 CSS// 3. Tree Shaking:移除未使用代码// Webpack production 模式自动启用4.3 CDN 加速
// 将静态资源部署到 CDN// 1. 就近访问,减少延迟// 2. 并行下载,突破浏览器并发限制// 3. 缓存资源,减少源站压力// 配置示例// JS/CSS:https://cdn.example.com/assets/app.abc123.js// 图片:https://cdn.example.com/images/photo.webp五、字体优化
// 1. 使用 font-display 控制加载行为@font-face{font-family:'MyFont';src:url('font.woff2')format('woff2');font-display:swap;// 先用系统字体,加载完成后替换}// 2. 预加载关键字体<link rel="preload"href="/fonts/main.woff2"as="font"type="font/woff2"crossorigin>// 3. 子集化:只包含需要的字符// 使用工具提取页面用到的字符子集六、缓存策略
// 1. Service Worker 缓存self.addEventListener('fetch',(event)=>{event.respondWith(caches.match(event.request).then((response)=>{returnresponse||fetch(event.request)}))})// 2. 本地存储// localStorage:持久化存储,5-10MB// sessionStorage:会话级存储// IndexedDB:大量结构化数据// 3. HTTP 缓存头配置// 静态资源:Cache-Control: public, max-age=31536000, immutable// HTML:Cache-Control: no-cache(每次都协商验证)七、性能监控
// 1. Performance APIconstpaint=performance.getEntriesByType('paint')constlcp=performance.getEntriesByType('largest-contentful-paint')// 2. Long Task 监控constobserver=newPerformanceObserver((list)=>{for(constentryoflist.getEntries()){console.warn('Long task:',entry.duration,'ms')}})observer.observe({entryTypes:['longtask']})// 3. 上报性能数据functionreportMetric(name,value){navigator.sendBeacon('/api/metrics',JSON.stringify({name,value,url:location.href,timestamp:Date.now()}))}八、易混淆点
- 防抖 vs 节流:防抖是"等你停下来",节流是"每隔一段时间"。防抖适用于搜索输入,节流适用于滚动事件。
- LCP vs FCP:FCP 是首次内容绘制,LCP 是最大内容绘制。LCP 更能反映用户感知的加载完成时间。
- 强缓存 vs 协商缓存:强缓存直接使用缓存不发请求;协商缓存发请求验证,返回 304 使用缓存。
- SSR vs SSG:SSR 每次请求时渲染,SSG 构建时生成静态 HTML。
九、思考与练习
1.Core Web Vitals 的三大指标是什么?理想值是多少?
解析:
- LCP(最大内容绘制):≤ 2.5 秒
- INP(交互到下次绘制):≤ 200 毫秒
- CLS(累积布局偏移):≤ 0.1
2.防抖和节流的区别是什么?各自的应用场景?
解析:
- 防抖:连续触发时只执行最后一次,适用于搜索输入、窗口 resize
- 节流:固定间隔内只执行一次,适用于滚动事件、鼠标移动
3.如何优化首屏加载时间?
解析:
- 代码分割,按路由懒加载
- 预加载关键资源(字体、CSS)
- SSR / SSG 减少白屏时间
- 图片懒加载和现代格式(WebP、AVIF)
- 骨架屏减少感知等待
4.虚拟列表的原理是什么?
解析:只渲染可视区域内的列表项,通过监听滚动事件动态计算可见项并渲染,大量数据时避免创建过多 DOM 节点。
5.强缓存和协商缓存的区别是什么?
解析:
- 强缓存:直接使用缓存,不发请求(Cache-Control: max-age)
- 协商缓存:发请求验证,返回 304 使用缓存(ETag / Last-Modified)
总结
- Core Web Vitals:LCP ≤ 2.5s、INP ≤ 200ms、CLS ≤ 0.1
- 首屏优化:代码分割、预加载、SSR/SSG、骨架屏、图片懒加载
- 运行时优化:虚拟列表、防抖节流、避免不必要渲染
- 网络优化:HTTP 缓存、Gzip/Brotli 压缩、CDN 加速
- 防抖节流:防抖等停执行,节流间隔执行
