性能优化
介绍
前端性能优化是提升用户体验、增加用户留存率和转化率的关键环节。一个性能优良的应用能够快速加载、流畅运行,给用户带来愉悦的体验。反之,性能不佳的应用会导致用户流失、转化率下降。本章将介绍前端性能优化的基本概念、核心原理和常用技术。
核心概念与原理
性能优化的目标
- 减少加载时间:缩短应用初始加载时间和后续资源加载时间
- 提升渲染性能:提高页面渲染速度和动画流畅度
- 减少资源消耗:降低CPU、内存和网络资源的消耗
- 优化用户体验:减少用户等待时间,提供即时反馈
- 提高可访问性:确保不同设备和网络环境下的良好体验
性能评估指标
- LCP (Largest Contentful Paint):最大内容绘制时间,衡量页面主要内容加载速度
- FID (First Input Delay):首次输入延迟,衡量页面交互响应速度
- CLS (Cumulative Layout Shift):累积布局偏移,衡量页面稳定性
- TTFB (Time to First Byte):首字节时间,衡量服务器响应速度
- FCP (First Contentful Paint):首次内容绘制时间,衡量页面开始加载的速度
- TTI (Time to Interactive):可交互时间,衡量页面变为完全可交互的时间
- 内存使用:应用运行时的内存占用
- 网络请求:网络请求的数量、大小和响应时间
性能优化的层次
- 网络层优化:减少网络请求、压缩资源、使用CDN等
- 资源层优化:优化HTML、CSS、JavaScript、图像和字体等资源
- 渲染层优化:优化DOM操作、减少重绘和回流、使用CSS动画等
- 架构层优化:代码拆分、懒加载、服务端渲染等
- 用户体验优化:骨架屏、渐进式加载、即时反馈等
性能优化模型图示
+------------------+ +------------------+ +------------------+
| 性能评估指标 | | 性能优化层次 | | 关键优化技术 |
+------------------+ +------------------+ +------------------+
| - LCP | | - 网络层优化 | | - 资源压缩 |
| - FID | | - 资源层优化 | | - 代码拆分 |
| - CLS | | - 渲染层优化 | | - 懒加载 |
| - TTFB | | - 架构层优化 | | - 缓存策略 |
| - FCP | | - 用户体验优化 | | - 图像优化 |
| - TTI | | | | - 预加载 |
| - 内存使用 | | | | - 服务端渲染 |
| - 网络请求 | | | | - 响应式图像 |
+------------------+ +------------------+ +------------------+
性能优化技术示例
网络层优化
资源压缩与合并
# 使用Gulp压缩CSS
const gulp = require('gulp');
const cleanCSS = require('gulp-clean-css');
gulp.task('minify-css', () => {
return gulp.src('src/css/*.css')
.pipe(cleanCSS({
compatibility: 'ie8'
}))
.pipe(gulp.dest('dist/css'));
});
# 使用Webpack压缩JavaScript
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: __dirname + '/dist'
},
optimization: {
minimize: true
}
};
缓存策略
// HTTP缓存控制(服务器端配置)
// Express示例
app.use(express.static('public', {
maxAge: '1d', // 静态资源缓存1天
etag: true, // 启用ETag
lastModified: true // 启用Last-Modified
}));
// 服务工作线程(Service Worker)缓存
self.addEventListener('install', event => {
event.waitUntil(
caches.open('my-app-cache-v1')
.then(cache => {
return cache.addAll([
'/',
'/index.html',
'/styles.css',
'/app.js',
'/logo.png'
]);
})
);
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
// 缓存命中,直接返回
if (response) {
return response;
}
// 缓存未命中,请求网络
return fetch(event.request);
})
);
});
资源层优化
图像优化
<!-- 使用响应式图像 -->
<picture>
<source srcset="image-large.webp" type="image/webp" media="(min-width: 1024px)">
<source srcset="image-medium.webp" type="image/webp" media="(min-width: 768px)">
<source srcset="image-small.webp" type="image/webp">
<source srcset="image-large.jpg" media="(min-width: 1024px)">
<source srcset="image-medium.jpg" media="(min-width: 768px)">
<img src="image-small.jpg" alt="Example image" loading="lazy">
</picture>
<!-- 使用SVG图标 -->
<svg class="icon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z" fill="currentColor"/>
</svg>
字体优化
/* 字体显示策略 */
@font-face {
font-family: 'MyFont';
src: url('myfont.woff2') format('woff2'),
url('myfont.woff') format('woff');
font-weight: 400;
font-style: normal;
font-display: swap; /* 优先使用系统字体显示,字体加载完成后替换 */
}
/* 字体子集化 - 只包含使用的字符 */
/* 可以使用工具如Font Squirrel或glyphhanger生成 */
渲染层优化
DOM操作优化
// 优化前 - 多次DOM操作
for (let i = 0; i < 1000; i++) {
document.getElementById('list').innerHTML += `<li>Item ${i}</li>`;
}
// 优化后 - 文档片段
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);
// 优化后 - 字符串拼接
let html = '';
for (let i = 0; i < 1000; i++) {
html += `<li>Item ${i}</li>`;
}
document.getElementById('list').innerHTML = html;
CSS优化
/* 避免CSS表达式 */
/* 优化前 */
.element {
width: expression(document.body.clientWidth > 800 ? "800px" : "auto");
}
/* 优化后 - 使用媒体查询 */
@media (min-width: 800px) {
.element {
width: 800px;
}
}
/* 避免深层次选择器 */
/* 优化前 */
body div.container ul.menu li a {
color: #000;
}
/* 优化后 */
.menu-link {
color: #000;
}
架构层优化
代码拆分与懒加载
// Webpack代码拆分
// 1. 动态导入
function loadComponent() {
return import('./component').then(component => {
return component.default;
});
}
// 2. React懒加载
import React, { lazy, Suspense } from 'react';
const LazyComponent = lazy(() => import('./LazyComponent'));
function App() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
</div>
);
}
// 3. Vue懒加载
const routes = [
{
path: '/lazy',
component: () => import('./LazyComponent.vue')
}
];
服务端渲染(SSR)与静态生成(SSG)
// Next.js示例 - 服务端渲染
export async function getServerSideProps(context) {
const res = await fetch(`https://api.example.com/data`);
const data = await res.json();
return {
props: { data }, // 将数据传递给组件
};
}
function Page({ data }) {
return (
<div>
<h1>Server-Side Rendered Page</h1>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}
export default Page;
// Next.js示例 - 静态生成
export async function getStaticProps() {
const res = await fetch(`https://api.example.com/data`);
const data = await res.json();
return {
props: { data },
revalidate: 60, // 每60秒重新生成页面
};
}
function Page({ data }) {
return (
<div>
<h1>Static Generated Page</h1>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}
export default Page;
解决方案
性能优化策略
- 测量优先:使用性能工具测量当前性能,确定优化目标
- 关键路径优化:优先优化影响用户体验的关键路径
- 渐进式优化:从小处着手,逐步提升性能
- 持续监控:建立性能监控体系,持续跟踪性能变化
- 数据驱动:基于性能数据制定优化策略
- 用户体验优先:在性能和功能之间找到平衡,优先保证良好的用户体验
核心优化技术
详细内容请参考:核心优化技术详解
- 资源压缩:压缩HTML、CSS、JavaScript、图像等资源
- 代码拆分:将代码拆分为多个小模块,按需加载
- 懒加载:延迟加载非关键资源(图像、组件等)
- 缓存策略:利用HTTP缓存、Service Worker缓存等
- 预加载:预加载关键资源
- 图像优化:使用适当的图像格式、尺寸和压缩率
- 字体优化:使用字体子集、适当的字体显示策略
- 服务端渲染/静态生成:提高首屏加载速度
- 减少重绘和回流:优化DOM操作和CSS
- 使用Web Workers:将耗时操作移至后台线程
- 响应式设计:针对不同设备优化体验
- 使用CDN:加速资源加载
最佳实践
详细内容请参考:性能优化最佳实践详解
- 最小化资源大小:删除未使用的代码和资源
- 减少HTTP请求:合并资源、使用CSS精灵图等
- 优化关键渲染路径:内联关键CSS,延迟加载非关键JavaScript
- 避免阻塞渲染:使用async/defer属性加载JavaScript
- 使用适当的缓存策略:为不同类型的资源设置合适的缓存时间
- 优化图像:使用WebP、AVIF等现代图像格式
- 使用SVG图标:代替位图图标
- 避免字体闪烁:使用font-display: swap
- 优化动画性能:使用CSS transforms和opacity实现动画
- 减少DOM节点数量:简化HTML结构
- 使用虚拟滚动:处理长列表
- 定期清理内存:避免内存泄漏
- 性能预算:设置性能预算,确保应用性能在可接受范围内
- 自动化性能测试:将性能测试集成到CI/CD流程中
工具推荐
- 性能测量工具:
- Lighthouse:Google开发的网页性能评估工具
- WebPageTest:网页性能测试工具
- Chrome DevTools:Chrome浏览器开发工具
- Firefox DevTools:Firefox浏览器开发工具
- Safari Web Inspector:Safari浏览器开发工具
- 资源优化工具:
- Gzip/Brotli:资源压缩
- Terser:JavaScript压缩
- CSSNano:CSS压缩
- html-minifier:HTML压缩
- ImageOptim:图像优化
- Squoosh:在线图像优化工具
- SVGO:SVG优化工具
- 构建工具:
- Webpack:模块打包工具
- Rollup:JavaScript模块打包工具
- Parcel:零配置打包工具
- Gulp:任务自动化工具
- 监控工具:
- New Relic:应用性能监控
- Datadog:性能监控平台
- Sentry:错误监控平台
- LogRocket:用户体验监控
- 框架优化工具:
- React.memo/useMemo/useCallback:React性能优化
- Vue的keep-alive:Vue组件缓存
- Angular的ChangeDetectionStrategy:变更检测策略
- 服务端渲染/静态生成框架:
- Next.js:React框架
- Nuxt.js:Vue框架
- Gatsby:React静态站点生成器
- Angular Universal:Angular服务端渲染
- 其他工具:
- ServiceWorker:离线缓存
- Workbox:Service Worker工具库
- Preload/Prefetch:资源预加载
- Critical CSS:关键CSS提取工具