Appearance
性能优化基础概念
性能优化是提升Web应用程序速度、响应性和用户体验的关键过程。良好的性能不仅能提高用户满意度,还能改善SEO排名和业务指标。本章将介绍性能优化的基本概念、重要指标和优化策略。
性能的重要性
用户体验影响
性能对用户体验有着直接的影响:
- 加载时间:页面加载时间每增加1秒,转化率可能下降7%
- 响应速度:用户期望页面在3秒内加载完成
- 交互流畅度:动画和交互应保持60fps的流畅度
- 用户留存:性能提升可以显著提高用户留存率
业务影响
- 转化率:Amazon发现页面加载时间每增加100毫秒,收入下降1%
- SEO排名:Google将页面速度作为搜索排名因素
- 运营成本:优化的代码和资源可以降低服务器成本
- 品牌形象:快速响应的应用提升品牌信誉
关键性能指标(Core Web Vitals)
Google定义了三个关键的用户体验指标:
1. 最大内容绘制(LCP - Largest Contentful Paint)
衡量加载性能,目标是在2.5秒内完成。
javascript
// 监测LCP
import { getLCP } from 'web-vitals';
getLCP(console.log);
2. 首次输入延迟(FID - First Input Delay)
衡量交互响应性,目标是小于100毫秒。
javascript
// 监测FID
import { getFID } from 'web-vitals';
getFID(console.log);
3. 累积布局偏移(CLS - Cumulative Layout Shift)
衡量视觉稳定性,目标是小于0.1。
javascript
// 监测CLS
import { getCLS } from 'web-vitals';
getCLS(console.log);
性能测量工具
1. Lighthouse
Google的开源自动化工具,用于改进网页质量。
bash
# 命令行使用
npx lighthouse https://example.com --output json --output-path report.json
2. Web Vitals库
轻量级库,用于测量核心Web指标。
javascript
import {
getCLS,
getFID,
getFCP,
getLCP,
getTTFB
} from 'web-vitals';
// 发送性能数据到分析服务
function sendToAnalytics(metric) {
const body = JSON.stringify(metric);
const url = 'https://example.com/analytics';
// 使用sendBeacon发送数据
if (navigator.sendBeacon) {
navigator.sendBeacon(url, body);
} else {
fetch(url, { body, method: 'POST', keepalive: true });
}
}
getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getFCP(sendToAnalytics);
getLCP(sendToAnalytics);
getTTFB(sendToAnalytics);
3. Performance API
浏览器内置的性能测量工具。
javascript
// 测量特定操作的性能
function measureFunctionPerformance(fn, name) {
performance.mark(`${name}-start`);
const result = fn();
performance.mark(`${name}-end`);
performance.measure(name, `${name}-start`, `${name}-end`);
const measure = performance.getEntriesByName(name)[0];
console.log(`${name} took ${measure.duration} milliseconds`);
return result;
}
// 获取性能数据
function getPerformanceData() {
const perfData = performance.getEntriesByType('navigation')[0];
return {
dnsTime: perfData.domainLookupEnd - perfData.domainLookupStart,
tcpTime: perfData.connectEnd - perfData.connectStart,
requestTime: perfData.responseStart - perfData.requestStart,
responseTime: perfData.responseEnd - perfData.responseStart,
domLoadTime: perfData.domContentLoadedEventEnd - perfData.navigationStart
};
}
性能优化策略
1. 资源优化
压缩和缩小
javascript
// Webpack配置示例
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true, // 移除console语句
},
},
}),
],
},
};
图片优化
html
<!-- 响应式图片 -->
<picture>
<source media="(min-width: 800px)" srcset="large.webp" type="image/webp">
<source media="(min-width: 800px)" srcset="large.jpg" type="image/jpeg">
<source srcset="small.webp" type="image/webp">
<img src="small.jpg" alt="描述" loading="lazy">
</picture>
<!-- 使用srcset提供多种分辨率 -->
<img src="image-400.jpg"
srcset="image-400.jpg 400w,
image-800.jpg 800w,
image-1200.jpg 1200w"
sizes="(max-width: 600px) 400px,
(max-width: 1000px) 800px,
1200px"
alt="响应式图片">
2. 代码分割和懒加载
javascript
// 动态导入实现代码分割
const loadModule = async () => {
const { heavyFunction } = await import('./heavy-module');
return heavyFunction();
};
// React中的懒加载组件
import { lazy, Suspense } from 'react';
const LazyComponent = lazy(() => import('./LazyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}
3. 缓存策略
javascript
// HTTP缓存头设置
app.use((req, res, next) => {
// 静态资源长期缓存
if (req.url.match(/\.(js|css|png|jpg|jpeg|gif|ico|svg)$/)) {
res.setHeader('Cache-Control', 'public, max-age=31536000'); // 1年
} else {
// HTML文件不缓存
res.setHeader('Cache-Control', 'no-cache');
}
next();
});
4. 预加载策略
html
<!-- 预加载关键资源 -->
<link rel="preload" href="critical.css" as="style">
<link rel="preload" href="hero-image.jpg" as="image">
<link rel="preload" href="critical.js" as="script">
<!-- 预连接到外部域 -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<!-- DNS预获取 -->
<link rel="dns-prefetch" href="//fonts.googleapis.com">
前端性能优化
1. JavaScript优化
javascript
// 避免内存泄漏
class Component {
constructor() {
this.handleResize = this.handleResize.bind(this);
window.addEventListener('resize', this.handleResize);
}
handleResize() {
// 处理resize事件
}
destroy() {
// 移除事件监听器
window.removeEventListener('resize', this.handleResize);
}
}
// 使用requestIdleCallback处理非关键任务
function nonCriticalTask() {
if ('requestIdleCallback' in window) {
requestIdleCallback(doWork);
} else {
setTimeout(doWork, 1);
}
}
function doWork(deadline) {
while (deadline.timeRemaining() > 0 && tasks.length > 0) {
performTask();
}
if (tasks.length > 0) {
requestIdleCallback(doWork);
}
}
2. CSS优化
css
/* 避免复杂选择器 */
/* 不好的做法 */
div.container ul li span.highlighted {
color: red;
}
/* 好的做法 */
.highlighted-text {
color: red;
}
/* 使用transform和opacity进行动画 */
.animate-element {
/* 避免改变layout或paint的属性 */
transform: translateX(100px); /* 好 - 只影响composite */
opacity: 0.5; /* 好 - 只影响composite */
}
/* 避免 */
.bad-animation {
width: 200px; /* 不好 - 影响layout */
height: 200px; /* 不好 - 影响layout */
background-color: red; /* 不好 - 可能影响paint */
}
后端性能优化
1. 数据库查询优化
javascript
// 使用索引优化查询
// 在数据库中为经常查询的字段创建索引
// SELECT * FROM users WHERE email = 'user@example.com'; -- email字段应该有索引
// 避免N+1查询问题
const getUsersWithPosts = async () => {
// 不好的做法 - N+1查询
// const users = await User.findAll();
// for (const user of users) {
// user.posts = await Post.findAll({ where: { userId: user.id }});
// }
// 好的做法 - 单次查询
const users = await User.findAll({
include: [{ model: Post }]
});
return users;
};
// 分页查询大数据集
const getUsersPaginated = async (page = 1, limit = 10) => {
const offset = (page - 1) * limit;
return await User.findAndCountAll({
limit,
offset,
order: [['createdAt', 'DESC']]
});
};
2. 缓存实现
javascript
// Redis缓存示例
const redis = require('redis');
const client = redis.createClient();
const getCachedData = async (key, fetchFunction) => {
// 尝试从缓存获取
const cached = await client.get(key);
if (cached) {
return JSON.parse(cached);
}
// 缓存未命中,从数据库获取
const data = await fetchFunction();
// 存储到缓存(1小时过期)
await client.setex(key, 3600, JSON.stringify(data));
return data;
};
// 使用示例
const getUser = async (id) => {
return await getCachedData(
`user:${id}`,
() => User.findByPk(id)
);
};
性能监控
1. 实时监控
javascript
// 性能监控类
class PerformanceMonitor {
constructor() {
this.metrics = new Map();
}
startTimer(name) {
this.metrics.set(name, performance.now());
}
endTimer(name) {
const start = this.metrics.get(name);
if (start) {
const duration = performance.now() - start;
console.log(`${name} took ${duration.toFixed(2)} milliseconds`);
this.metrics.delete(name);
return duration;
}
}
// 监控API调用性能
async monitorAPICall(url, options = {}) {
this.startTimer(`api-${url}`);
try {
const response = await fetch(url, options);
const duration = this.endTimer(`api-${url}`);
// 如果请求时间过长,记录警告
if (duration > 1000) {
console.warn(`Slow API call: ${url} took ${duration}ms`);
}
return response;
} catch (error) {
this.endTimer(`api-${url}`);
throw error;
}
}
}
const perfMonitor = new PerformanceMonitor();
2. 性能预算
javascript
// 性能预算配置
const performanceBudget = {
metrics: {
lcp: 2500, // 2.5秒
fid: 100, // 100毫秒
cls: 0.1, // 0.1
fcp: 1800, // 1.8秒
ttfb: 200 // 200毫秒
},
resourceSizes: {
javascript: 250 * 1024, // 250KB
css: 50 * 1024, // 50KB
images: 1024 * 1024 // 1MB
},
resourceCounts: {
requests: 50
}
};
// 验证性能预算
function checkPerformanceBudget(metrics) {
const violations = [];
Object.keys(performanceBudget.metrics).forEach(key => {
if (metrics[key] > performanceBudget.metrics[key]) {
violations.push({
metric: key,
actual: metrics[key],
budget: performanceBudget.metrics[key]
});
}
});
return violations;
}
性能优化检查清单
构建时优化
- [ ] 启用代码压缩和缩小
- [ ] 实现代码分割
- [ ] 移除未使用的代码(Tree Shaking)
- [ ] 使用长期缓存的文件名
- [ ] 启用Gzip/Brotli压缩
运行时优化
- [ ] 实现资源懒加载
- [ ] 优化关键渲染路径
- [ ] 使用适当的缓存策略
- [ ] 优化图片和媒体资源
- [ ] 减少HTTP请求数量
- [ ] 使用CDN分发静态资源
监控和维护
- [ ] 设置性能监控
- [ ] 定期进行性能审计
- [ ] 实施性能预算
- [ ] 持续优化和测试
总结
性能优化是一个持续的过程,需要在开发、测试和生产环境中不断监控和改进。通过理解性能指标、采用合适的优化策略和工具,可以显著提升Web应用程序的性能和用户体验。在接下来的章节中,我们将深入探讨各种具体的性能优化技术和实践。