前端性能优化清单与实践

性能优化是前端开发中非常重要的一环。用户对页面加载速度的容忍度只有几秒,加载太慢会导致用户流失。这篇总结前端性能优化的常用手段。


一、加载性能优化

1.1 减少请求数量

资源合并

<!-- 多个CSS合并成一个 -->
<link rel="stylesheet" href="bundle.css">

<!-- 多个JS合并成一个 -->
<script src="bundle.js"></script>

雪碧图

将多个小图标合并为一张图片,减少请求数:

.icon {
background-image: url(sprite.png);
background-position: -10px -20px;
}

内联资源

对于很小的资源,可以直接内联:

<!-- 内联 small SVG -->
<svg><path d="..."/></svg>

<!-- 内联 small CSS -->
<style>.small{color:red;}</style>

1.2 减少资源体积

代码压缩

  • HTML、CSS、JS 启用压缩
  • 使用构建工具(Terser、CSSNano)

图片压缩

  • 使用 WebP 格式
  • 压缩 PNG、JPEG
  • 使用 TinyPNG 等工具

Tree Shaking

使用 ES6 模块 + 构建工具自动删除未使用代码:

// 只引入使用的方法
import { debounce } from 'lodash';

1.3 缓存策略

强缓存

# Nginx 配置
location ~* \.(css|js|jpg|png)$ {
expires 7d;
add_header Cache-Control: public;
}

协商缓存

location ~* \.(css|js)$ {
add_header Last-Modified $date_gmt;
add_header ETag $request_id;
}

1.4 懒加载

图片懒加载

<img src="placeholder.jpg" data-src="real-image.jpg" class="lazy">

<script>
const lazyImages = document.querySelectorAll('.lazy');
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.src = entry.target.dataset.src;
observer.unobserve(entry.target);
}
});
});
lazyImages.forEach(img => observer.observe(img));
</script>

路由懒加载

// Vue
const routes = [
{ path: '/home', component: () => import('./views/Home.vue') }
];

// React
const Home = lazy(() => import('./Home'));

二、渲染性能优化

2.1 避免布局抖动(Layout Thrashing)

问题代码

// 多次读取 + 多次写入,导致多次重排
elements.forEach(el => {
const width = el.offsetWidth; // 读取
el.style.width = width * 2 + 'px'; // 写入
});

优化方案:分离读写

// 先统一读取
const widths = elements.map(el => el.offsetWidth);
// 再统一写入
elements.forEach((el, i) => {
el.style.width = widths[i] * 2 + 'px';
});

2.2 使用 CSS 变换

/* 优化前:触发重排 */
.box {
top: 100px;
left: 100px;
}

/* 优化后:只触发重绘 */
.box {
transform: translate(100px, 100px);
}

2.3 减少重绘重排

使用 class 批量修改

// 优化前
element.style.width = '100px';
element.style.height = '100px';
element.style.margin = '10px';

// 优化后
element.classList.add('new-style');

避免以下属性

  • widthheightmarginpadding
  • topleftrightbottom
  • offsetWidthoffsetHeight

使用以下属性只会触发重绘,不触发重排:

  • transform
  • opacity
  • filter

2.4 启用 GPU 加速

.animated {
transform: translateZ(0);
will-change: transform; /* 提示浏览器提前准备 */
}

三、图片优化

3.1 选择合适的格式

格式 适用场景 特点
JPEG 照片、复杂图像 体积小
PNG 图标、需要透明 支持透明、质量高
WebP 通用场景 体积更小
SVG 图标、简单图形 可缩放、体积小
AVIF 现代浏览器 体积最小

3.2 响应式图片

<img srcset="small.jpg 480w,
medium.jpg 800w,
large.jpg 1200w"
sizes="(max-width: 480px) 100vw,
(max-width: 800px) 80vw,
60vw"
src="medium.jpg"
alt="描述">

3.3 图片加载策略

<!-- 关键图片预加载 -->
<link rel="preload" as="image" href="hero.jpg">

<!-- 防止图片加载阻塞渲染 -->
<img src="photo.jpg" loading="lazy" alt="...">

四、JavaScript 优化

4.1 防抖与节流

防抖(Debounce):等用户停止操作后才执行

function debounce(fn, delay) {
let timer = null;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}

// 使用
window.addEventListener('resize', debounce(() => {
console.log('resize');
}, 300));

节流(Throttle):限制执行频率

function throttle(fn, limit) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
fn.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}

// 使用
window.addEventListener('scroll', throttle(() => {
console.log('scroll');
}, 200));

4.2 虚拟滚动

长列表渲染优化:

// 使用 react-virtualized 或 vue-virtual-scroll-list
// 只渲染可见区域的元素

4.3 Web Worker

处理耗时计算:

// worker.js
self.onmessage = ({ data }) => {
const result = heavyComputation(data);
self.postMessage(result);
};

// main.js
const worker = new Worker('worker.js');
worker.postMessage(largeData);
worker.onmessage = ({ data }) => {
console.log('结果:', data);
};

五、字体优化

5.1 字体加载策略

<!-- preload 关键字体 -->
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>

<!-- 使用 font-display -->
@font-face {
font-family: 'MyFont';
src: url('font.woff2') format('woff2');
font-display: swap; /* 先用系统字体,显示后再替换 */
}

5.2 字体子集化

只加载使用的字符:

@font-face {
src: url('subset.woff2') format('woff2');
unicode-range: U+4e00-9fff; /* 只加载中文常用字 */
}

六、关键渲染路径优化

6.1 关键 CSS 内联

<head>
<style>
/* 关键 CSS 内联 */
.header { background: #333; color: #fff; }
.hero { height: 500px; }
</style>
</head>

6.2 非关键 CSS 异步加载

<link rel="stylesheet" href="non-critical.css" media="print" onload="this.media='all'">

6.3 脚本加载顺序

<!-- 关键脚本 defer -->
<script src="main.js" defer></script>

<!-- 非关键脚本 async -->
<script src="analytics.js" async></script>

七、性能监测工具

工具 用途
Lighthouse 综合性能审计
Chrome DevTools 性能分析
WebPageTest 页面加载分析
Performance API 实时监测
// 使用 Performance API
const timing = performance.getEntriesByType('navigation')[0];
console.log('DNS:', timing.domainLookupEnd - timing.domainLookupStart);
console.log('TCP:', timing.connectEnd - timing.connectStart);
console.log('DOM:', timing.domContentLoadedEventEnd - timing.navigationStart);

八、优化清单

加载阶段

  • 启用 gzip 压缩
  • 合并 CSS/JS 文件
  • 图片使用 WebP 格式
  • 静态资源 CDN 加速
  • 启用浏览器缓存
  • 关键 CSS 内联

渲染阶段

  • 避免布局抖动
  • 使用 transform/opacity 做动画
  • 减少重绘重排
  • 使用 will-change 提前准备

交互阶段

  • 事件防抖/节流
  • 长列表虚拟滚动
  • Web Worker 处理计算

性能优化是持续的过程,建议定期用 Lighthouse 检测,发现问题及时优化。有其他问题欢迎留言!