概述
前端性能优化直接影响用户体验和业务转化率。研究表明,页面加载时间每增加 1 秒,转化率下降约 7%。本文从网络、渲染、代码、图片四个维度梳理常用的优化手段,并介绍性能度量工具。
网络层优化
减少 HTTP 请求
每个 HTTP 请求都有建立连接的开销。减少请求数量是最直接的优化方式:
- 合并 CSS/JS 文件(构建工具如 Webpack 自动完成)
- 使用 CSS Sprites 合并小图标
- 内联关键 CSS(Critical CSS)
CDN 加速
将静态资源部署到 CDN 节点,利用就近访问原则缩短网络传输距离:
// 将静态资源指向 CDN 域名
const CDN_BASE = 'https://cdn.example.com';
function getAssetUrl(path) {
return `${CDN_BASE}/${path}?v=${VERSION}`;
}
资源压缩
开启 Gzip/Brotli 压缩,通常能减少 60%-80% 的传输体积:
# Nginx 配置示例
gzip on;
gzip_types text/plain text/css application/json application/javascript;
gzip_min_length 1024;
缓存策略
合理使用 HTTP 缓存减少重复请求:
- 强缓存:
Cache-Control: max-age=31536000,适合带 hash 的静态资源 - 协商缓存:
ETag/Last-Modified,适合频繁更新的 HTML - Service Worker:离线缓存,精确控制缓存策略
// Service Worker 缓存示例
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(cached => {
return cached || fetch(event.request).then(response => {
const clone = response.clone();
caches.open('v1').then(cache => cache.put(event.request, clone));
return response;
});
})
);
});
渲染层优化
关键渲染路径
浏览器渲染流程:HTML → DOM → CSSOM → Render Tree → Layout → Paint → Composite。优化的目标是让首屏内容尽快完成渲染。
- 内联首屏关键 CSS,避免阻塞渲染
- 将非关键 JS 标记为
async或defer - 减少 DOM 节点数量
<!-- async: 下载不阻塞,下载完立即执行 -->
<script async src="analytics.js"></script>
<!-- defer: 下载不阻塞,DOM 解析完再执行,保持顺序 -->
<script defer src="app.js"></script>
避免重排与重绘
重排(Reflow)比重绘(Repaint)开销更大。以下操作会触发重排:
- 修改元素尺寸、位置
- 读取
offsetWidth、clientHeight等布局属性 - 增删 DOM 节点
// 反面示例:多次触发重排
for (let i = 0; i < 100; i++) {
element.style.left = element.offsetLeft + 1 + 'px';
}
// 正确做法:批量修改,一次重排
const left = element.offsetLeft;
element.style.left = left + 100 + 'px';
使用 DocumentFragment 批量操作 DOM:
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
const li = document.createElement('li');
li.textContent = `Item ${i}`;
fragment.appendChild(li);
}
document.getElementById('list').appendChild(fragment);
CSS 加载优化
- CSS 放在
<head>中,尽早开始解析 - 避免使用
@import(会串行加载) - 使用
will-change提示浏览器创建独立图层
/* 告知浏览器该元素即将变化,提前创建合成层 */
.animated-element {
will-change: transform;
}
代码层优化
懒加载
按需加载非首屏资源,减少初始加载体积:
// 路由级懒加载(React 示例)
const Detail = React.lazy(() => import('./pages/Detail'));
// 图片懒加载(Intersection Observer)
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);
});
防抖与节流
高频事件(scroll、resize、input)需要控制回调执行频率:
// 防抖:停止触发后才执行(适合搜索输入)
function debounce(fn, delay) {
let timer = null;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
// 节流:固定间隔执行一次(适合滚动事件)
function throttle(fn, interval) {
let lastTime = 0;
return function (...args) {
const now = Date.now();
if (now - lastTime >= interval) {
lastTime = now;
fn.apply(this, args);
}
};
}
// 使用
window.addEventListener('scroll', throttle(handleScroll, 100));
input.addEventListener('input', debounce(search, 300));
Web Worker
将 CPU 密集型任务移到 Worker 线程,避免阻塞主线程:
// main.js
const worker = new Worker('compute.js');
worker.postMessage({ data: largeArray });
worker.onmessage = event => {
console.log('计算结果:', event.data);
};
// compute.js
self.onmessage = event => {
const result = heavyComputation(event.data);
self.postMessage(result);
};
图片优化
格式选择
| 格式 | 特点 | 适用场景 |
|---|---|---|
| JPEG | 有损压缩,体积小 | 照片、渐变色图片 |
| PNG | 无损压缩,支持透明 | 图标、需要透明的图片 |
| WebP | 体积比 JPEG 小 25-30% | 现代浏览器通用 |
| SVG | 矢量,无限缩放 | 图标、Logo |
响应式图片
根据设备分辨率加载不同尺寸的图片:
<picture>
<source srcset="image.webp" type="image/webp">
<source srcset="image-800.jpg" media="(max-width: 800px)">
<img src="image-1200.jpg" alt="responsive image">
</picture>
图片压缩策略
- 使用构建工具自动压缩(imagemin)
- 设置合理的质量参数(JPEG 80% 通常肉眼无差别)
- 大图使用渐进式 JPEG(Progressive JPEG),先显示模糊轮廓再逐步清晰
性能度量
Performance API
浏览器内置的性能测量接口:
// 测量关键指标
const timing = performance.timing;
const metrics = {
dns: timing.domainLookupEnd - timing.domainLookupStart,
tcp: timing.connectEnd - timing.connectStart,
ttfb: timing.responseStart - timing.requestStart,
domReady: timing.domContentLoadedEventEnd - timing.navigationStart,
load: timing.loadEventEnd - timing.navigationStart
};
// 使用 Performance Observer 监听 LCP
const observer = new PerformanceObserver(list => {
const entries = list.getEntries();
const lcp = entries[entries.length - 1];
console.log('LCP:', lcp.startTime);
});
observer.observe({ type: 'largest-contentful-paint', buffered: true });
Lighthouse
Google 提供的自动化审计工具,从五个维度评估页面质量:
- Performance(性能)
- Accessibility(无障碍)
- Best Practices(最佳实践)
- SEO
- PWA
可以通过 Chrome DevTools、命令行或 CI 集成使用:
# 命令行审计
npx lighthouse https://example.com --output=json --output-path=./report.json
核心 Web 指标
Google 定义的三个关键体验指标:
- LCP(Largest Contentful Paint):最大内容渲染时间,目标 < 2.5s
- FID(First Input Delay):首次输入延迟,目标 < 100ms
- CLS(Cumulative Layout Shift):累积布局偏移,目标 < 0.1
小结
前端优化不是一次性工作,而是持续的过程。优先处理影响最大的问题:
- 先度量,找到瓶颈所在
- 网络优化投入产出比最高(缓存、压缩、CDN)
- 渲染优化关注关键渲染路径
- 代码优化按需进行,避免过早优化
性能优化的核心原则:减少传输量、减少请求数、减少计算量、延迟非关键资源。