前端性能优化完全指南(从入门到实践)
一、为什么要做性能优化
用户访问一个网站,如果3秒内没有加载完成,53%的用户会选择离开。性能优化不仅影响用户体验,还直接影响转化率、SEO排名和品牌形象。
本文从网络请求、资源加载、渲染优化、代码层面四个维度,系统性地介绍前端性能优化的方法。
二、网络请求优化
1. 减少HTTP请求数量
每个HTTP请求都有DNS解析、TCP连接、等待响应等耗时。减少请求数量是最直接有效的优化手段。
- 合并文件:将多个CSS/JS文件合并为一个
- 使用雪碧图:将多张小图标合并为一张大图
- 内联小资源:小于10KB的图片或CSS直接内联
2. 使用HTTP/2
HTTP/2支持多路复用,可以在一个TCP连接上并行发送多个请求,大大降低了延迟。如果服务器支持,建议升级到HTTP/2。
3. 减少重定向
每次重定向都会增加一次完整的HTTP请求-响应周期,应该尽量避免不必要的重定向。
三、资源加载优化
1. 图片优化
图片通常是页面体积最大的部分,优化图片能显著提升加载速度。
- 选择合适的格式:照片用JPEG,图标用PNG/SVG,复杂动画用WebP
- 压缩图片:使用TinyPNG等工具压缩,可减少30%-50%体积
- 响应式图片:使用srcset属性为不同屏幕尺寸提供不同分辨率的图片
- 懒加载:可视区域外的图片延迟加载
// 图片懒加载示例
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target
img.src = img.dataset.src
observer.unobserve(img)
}
})
})
document.querySelectorAll('img[data-src]').forEach(img => {
observer.observe(img)
})
2. 使用CDN
CDN将资源部署到离用户最近的节点,能大幅减少网络延迟。对于静态资源(图片、CSS、JS),强烈建议使用CDN。
3. 资源预加载
使用link标签的rel属性,可以告诉浏览器提前加载某些资源。
四、渲染优化
1. 关键渲染路径优化
浏览器从收到HTML到渲染出像素的过程,称为关键渲染路径。优化目标是尽快完成首次渲染。
- 内联关键CSS:将首屏所需的CSS内联到head中
- 异步加载非关键CSS:使用media属性或loadCSS方案
- 将JS放在底部:或使用async/defer属性异步加载
2. 避免重排和重绘
重排(Reflow)是浏览器重新计算元素位置和大小的过程,开销最大。重绘(Repaint)是重新绘制元素外观的过程,开销次之。
// 不好的写法:多次触发重排
for (let i = 0; i < 100; i++) {
element.style.width = i + 'px'
element.style.height = i + 'px'
}
// 好的写法:一次性修改
element.style.cssText = 'width: 100px; height: 100px;'
// 或者使用class切换
element.classList.add('new-size')
3. 使用transform和opacity做动画
这两个属性只会触发合成(Composite),不会触发重排和重绘,动画性能最好。
// 高性能动画
.element {
transition: transform 0.3s ease;
}
.element:hover {
transform: translateX(10px);
}
五、代码层面优化
1. 路由懒加载
在Vue/React项目中,将不同路由的组件拆分成独立的代码块,只有在访问该路由时才加载。
// Vue路由懒加载
const routes = [
{
path: '/about',
component: () => import('./views/About.vue')
},
{
path: '/dashboard',
component: () => import('./views/Dashboard.vue')
}
]
2. 组件懒加载
对于非首屏的组件,也可以使用懒加载。
// 组件懒加载
components: {
'heavy-chart': () => import('./components/HeavyChart.vue')
}
3. 防抖和节流
对于频繁触发的事件(滚动、输入、窗口resize),使用防抖或节流减少处理次数。
// 防抖:延迟执行,适合输入框搜索
function debounce(fn, delay) {
let timer = null
return function() {
clearTimeout(timer)
timer = setTimeout(() => fn.apply(this, arguments), delay)
}
}
// 节流:固定频率执行,适合滚动加载
function throttle(fn, interval) {
let lastTime = 0
return function() {
const now = Date.now()
if (now - lastTime >= interval) {
fn.apply(this, arguments)
lastTime = now
}
}
}
4. 使用Web Worker处理复杂计算
长时间运行的JS任务会阻塞主线程,影响页面响应。使用Web Worker在后台线程执行。
// main.js
const worker = new Worker('worker.js')
worker.postMessage(data)
worker.onmessage = (e) => {
console.log('计算结果:', e.data)
}
// worker.js
self.onmessage = (e) => {
// 执行复杂计算
const result = heavyComputation(e.data)
self.postMessage(result)
}
六、缓存策略
1. 浏览器缓存
合理配置HTTP缓存头,可以让浏览器缓存静态资源,减少重复请求。
- Cache-Control:设置max-age、immutable等
- ETag:验证资源是否有变化
- Last-Modified:资源最后修改时间
2. 使用Service Worker
Service Worker可以实现离线缓存、消息推送等高级功能,是PWA的核心技术。
// 注册Service Worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js').then(reg => {
console.log('注册成功', reg.scope)
})
}
// sw.js:缓存静态资源
const CACHE_NAME = 'my-site-v1'
const urlsToCache = [
'/',
'/styles/main.css',
'/scripts/main.js'
]
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME).then(cache => cache.addAll(urlsToCache))
)
})
七、性能监控
优化完成后,还需要持续监控性能,确保效果持久。
1. Lighthouse
Chrome DevTools自带的Lighthouse工具,可以生成详细的性能报告和改进建议。
2. Web Vitals
Google推出的Core Web Vitals(核心网页指标),包括:
- LCP(最大内容绘制):衡量加载速度,应小于2.5秒
- INP(交互延迟):衡量交互响应,应小于200毫秒
- CLS(累计布局偏移):衡量视觉稳定性,应小于0.1
// 使用web-vitals库监控
import {onLCP, onINP, onCLS} from 'web-vitals'
onLCP(console.log)
onINP(console.log)
onCLS(console.log)
八、总结
性能优化是一个持续的过程,不是一次性的工作。建议按照以下顺序进行:
- 使用Lighthouse分析现状,找出瓶颈
- 优先处理影响最大的问题(通常是图片和网络请求)
- 实施优化后再次测试,验证效果
- 建立持续监控机制,防止性能退化
记住一个原则:不要过早优化,但也不要忽视优化。在保证代码可维护性的前提下,针对实际出现的性能问题,采取合适的优化手段。
参考资料:
- Google Web Fundamentals - Performance
- MDN Web Docs - Performance
- Web Vitals官方文档