Skip to Content
Handbook第 8 章:📈 持续成长与进阶8.5 性能优化与最佳实践

8.5 性能优化与最佳实践

性能优化的层次

性能金字塔

用户体验 ╱ ╲ ╱ ╲ ╱ 业务层 ╲ ╱ ╲ ╱ 应用层 ╲ ╱ ╲ ╱ 系统层 ╲ ╱____________________╲ ╱ ╲ ╱ 网络层 ╲ ╱________________________╲ ╱ ╲ ╱ 硬件层 ╲ ╱________________________________╲

各层优化要点

硬件层 (20%提升) ├─ CPU:多核并行处理 ├─ 内存:增加RAM容量 ├─ 存储:SSD替代HDD └─ 网络:CDN加速 网络层 (50%提升) ├─ DNS解析:使用优质DNS服务商 ├─ 建立连接:HTTP/2, HTTP/3 ├─ 传输数据:压缩、缓存 └─ 地理分布:CDN全球节点 系统层 (30%提升) ├─ Web服务器:Nginx优化配置 ├─ 应用服务器:连接池优化 ├─ 数据库:索引、查询优化 └─ 缓存层:多级缓存策略 应用层 (70%提升) ├─ 代码层面:算法优化 ├─ 数据库:减少查询次数 ├─ 资源:图片压缩、懒加载 └─ 渲染:SSR、增量静态生成 业务层 (10%提升) ├─ 减少不必要请求 ├─ 合并操作 ├─ 异步处理 └─ 预加载关键数据

前端性能优化

核心 Web 指标 (Core Web Vitals)

LCP (Largest Contentful Paint)

目标:< 2.5秒 优化策略: 1. 关键资源优化 - 图片压缩 (WebP/AVIF) - 字体子集化 - CSS压缩 2. 资源加载优化 - 预加载关键资源 - 延迟加载非关键资源 - 使用CDN 3. 服务器优化 - 启用Gzip/Brotli压缩 - 设置合适的缓存头 - 优化服务器响应时间

FID (First Input Delay)INP (Interaction to Next Paint)

目标:< 100毫秒 优化策略: 1. 减少JavaScript执行时间 - 代码分割 (Code Splitting) - 移除未使用代码 - 使用Web Workers 2. 优化主线程 - 避免长时间任务 (>50ms) - 使用requestIdleCallback - 分解大任务为小任务 3. 优化事件处理 - 防抖/节流 - 使用Passive事件监听器 - 避免强制同步布局

CLS (Cumulative Layout Shift)

目标:< 0.1 优化策略: 1. 预留空间 - 固定图片尺寸 - 预留广告位 - 使用skeleton加载 2. 避免布局抖动 - 不动态插入内容 - 使用transform替代position - 避免字体闪烁 (font-display)

图片优化

响应式图片

// Next.js Image优化 import Image from 'next/image' // ✅ 正确:设置明确尺寸 <Image src="/hero.jpg" width={800} height={600} alt="Hero image" priority={true} // 预加载 placeholder="blur" blurDataURL="data:image/jpeg..." /> // ✅ 响应式图片 <Image src="/responsive-image.jpg" fill sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw" alt="Responsive image" /> // ✅ 现代格式 // 1. WebP (现代浏览器) // 2. AVIF (更高压缩比) // 3. PNG/JPG (回退) <picture> <source srcSet="/image.avif" type="image/avif" /> <source srcSet="/image.webp" type="image/webp" /> <img src="/image.jpg" alt="Image" /> </picture>

代码分割

路由级别分割

// ✅ Next.js动态导入 import dynamic from 'next/dynamic' // 组件懒加载 const HeavyComponent = dynamic( () => import('../components/HeavyComponent'), { loading: () => <p>Loading...</p>, ssr: false // 客户端渲染 } ) // 库懒加载 const Chart = dynamic(() => import('react-chartjs-2'), { ssr: false })

模块级分割

// 按需加载功能模块 const loadModule = async () => { const { expensiveFunction } = await import('../utils/expensive') return expensiveFunction() } // 使用Suspense <Suspense fallback={<Spinner />}> <HeavyContent /> </Suspense>

React 性能优化

组件优化

import { memo, useMemo, useCallback } from 'react' // 1. memo 避免不必要重渲染 const ExpensiveComponent = memo(({ data, onUpdate }) => { const processedData = useMemo(() => { return data.map(item => ({ ...item, processed: true })) }, [data]) const handleClick = useCallback((id) => { onUpdate(id) }, [onUpdate]) return ( <div> {processedData.map(item => ( <Item key={item.id} data={item} onClick={handleClick} /> ))} </div> ) }) // 2. 虚拟列表 (大量数据) import { FixedSizeList as List } from 'react-window' const VirtualizedList = ({ items }) => ( <List height={600} itemCount={items.length} itemSize={35} > {({ index, style }) => ( <div style={style}> {items[index]} </div> )} </List> ) // 3. useDeferredValue (React 18) const SearchResults = ({ query }) => { const deferredQuery = useDeferredValue(query) // 优先渲染输入框,延迟搜索结果 return ( <div> <input value={query} onChange={handleChange} /> <ExpensiveList query={deferredQuery} /> </div> ) }

服务端渲染优化

Next.js 优化

// 页面级别缓存 export const revalidate = 3600 // 1小时 // 生成静态参数 export async function generateStaticParams() { const posts = await fetchPosts() return posts.map(post => ({ slug: post.slug })) } // 组件级缓存 const data = await unstable_cache( () => fetchExpensiveData(), ['cache-key'], { revalidate: 3600 } )()

后端性能优化

数据库优化

索引策略

-- 1. 主键索引 (自动创建) CREATE TABLE users ( id UUID PRIMARY KEY, ... ); -- 2. 常用查询索引 CREATE INDEX idx_users_email ON users(email); CREATE INDEX idx_users_status ON users(status); -- 3. 复合索引 (多列查询) CREATE INDEX idx_orders_user_status ON orders(user_id, status); -- 4. 部分索引 (条件筛选) CREATE INDEX idx_active_users ON users(id) WHERE status = 'active'; -- 5. 表达式索引 CREATE INDEX idx_users_lower_email ON users(LOWER(email));

查询优化

-- ❌ 慢查询:N+1问题 SELECT * FROM users; -- 为每个用户查询订单 SELECT * FROM orders WHERE user_id = 1; SELECT * FROM orders WHERE user_id = 2; -- ... -- ✅ 快查询:JOIN优化 SELECT u.*, o.* FROM users u LEFT JOIN orders o ON u.id = o.user_id; -- ✅ 批量查询 -- 1. 先查询ID SELECT id FROM users WHERE status = 'active'; -- 2. 批量查询订单 SELECT * FROM orders WHERE user_id IN (/* IDs */); -- ✅ 分页优化 -- ❌ 偏移量大时慢 SELECT * FROM orders LIMIT 100000, 20; -- ✅ 游标分页 SELECT * FROM orders WHERE id > last_seen_id ORDER BY id LIMIT 20;

API 优化

响应优化

// 1. 字段选择 // ❌ 返回所有字段 const users = await db.users.findMany() // ✅ 只返回需要的字段 const users = await db.users.findMany({ select: { id: true, name: true, email: true } }) // 2. 数据压缩 import { gzipSync } from 'zlib' export async function GET() { const data = await getLargeDataset() // 压缩响应 const compressed = gzipSync(JSON.stringify(data)) return new Response(compressed, { headers: { 'Content-Type': 'application/json', 'Content-Encoding': 'gzip' } }) } // 3. 分页响应 export async function GET(request: Request) { const { searchParams } = new URL(request.url) const page = parseInt(searchParams.get('page') || '1') const limit = 20 const [data, total] = await Promise.all([ getPaginatedData(page, limit), getTotalCount() ]) return Response.json({ data, pagination: { page, limit, total, totalPages: Math.ceil(total / limit) } }) }

缓存策略

多级缓存

// L1: 内存缓存 (进程内) const memoryCache = new Map() async function getUser(id: string) { // 检查内存缓存 if (memoryCache.has(id)) { return memoryCache.get(id) } // L2: Redis缓存 const cached = await redis.get(`user:${id}`) if (cached) { const user = JSON.parse(cached) memoryCache.set(id, user) return user } // L3: 数据库查询 const user = await db.users.findUnique({ where: { id } }) // 写入缓存 await redis.setex(`user:${id}`, 3600, JSON.stringify(user)) memoryCache.set(id, user) return user } // L4: 应用级缓存 (Prisma) const user = await db.users.findUnique({ where: { id }, cache: { // 缓存5分钟 ttl: 300, tag: ['users'] } })

队列与异步

任务队列

// 使用Bull队列 import Queue from 'bull' const imageQueue = new Queue('image processing', { redis: 'redis://localhost:6379' }) // 添加任务 await imageQueue.add('resize', { imageId: '123', size: 'thumbnail' }, { attempts: 3, backoff: { type: 'exponential', delay: 2000 } }) // 处理任务 imageQueue.process('resize', async (job) => { const { imageId, size } = job.data // 图片处理逻辑 await processImage(imageId, size) return { processed: true } }) // 幂等性设计 // 确保重复执行不会产生副作用 async function processImage(imageId: string, size: string) { // 检查是否已处理 const exists = await checkIfProcessed(imageId, size) if (exists) { return { skipped: true } } // 处理图片 await resizeImage(imageId, size) // 标记为已处理 await markAsProcessed(imageId, size) return { processed: true } }

监控与测量

性能监控指标

前端监控

// Web Vitals 监控 import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals' function sendToAnalytics(metric) { // 发送到分析服务 console.log(metric) } getCLS(sendToAnalytics) getFID(sendToAnalytics) getFCP(sendToAnalytics) getLCP(sendToAnalytics) getTTFB(sendToAnalytics) // 自定义性能标记 performance.mark('start-task') // ... 执行任务 performance.mark('end-task') performance.measure('task-duration', 'start-task', 'end-task') const measure = performance.getEntriesByName('task-duration')[0] console.log(`任务耗时: ${measure.duration}ms`)

后端监控

// API响应时间监控 import { performance } from 'perf_hooks' export async function GET(request: Request) { const start = performance.now() try { const data = await getData() const duration = performance.now() - start // 记录慢查询 if (duration > 1000) { console.warn(`Slow query: ${duration}ms`) } return Response.json(data) } catch (error) { const duration = performance.now() - start console.error(`Error after ${duration}ms`, error) throw error } }

性能预算

性能预算清单

前端性能预算: 页面大小 ├─ HTML: < 50KB (压缩后) ├─ CSS: < 100KB (压缩后) ├─ JS: < 200KB (压缩后,总计) └─ Images: < 1MB 加载时间 ├─ 首屏渲染 (FCP): < 1.8s ├─ 最大内容绘制 (LCP): < 2.5s ├─ 交互响应 (INP): < 200ms └─ 布局稳定 (CLS): < 0.1 API性能预算: ├─ 简单查询: < 100ms ├─ 复杂查询: < 500ms ├─ 批处理任务: < 10s └─ 长时间任务: 异步处理 数据库性能预算: ├─ 简单查询: < 10ms ├─ 复杂查询: < 100ms ├─ 索引扫描: < 50ms └─ 全表扫描: 不允许

性能分析工具

Lighthouse CI

// lighthouserc.json { "ci": { "collect": { "url": ["http://localhost:3000"], "numberOfRuns": 3 }, "assert": { "assertions": { "categories:performance": ["error", {"minScore": 0.9}], "categories:accessibility": ["error", {"minScore": 0.9}], "categories:best-practices": ["error", {"minScore": 0.9}], "categories:seo": ["error", {"minScore": 0.9}] } } } }

APM 工具对比

性能监控工具 Sentry ✅ 优势: - 错误追踪专业 - 性能监控集成 - 免费额度充足 - 易用性好 ❌ 劣势: - 功能相对简单 - 自定义能力有限 DataDog ✅ 优势: - 功能全面 - 监控覆盖广 - 告警灵活 ❌ 劣势: - 价格昂贵 - 学习曲线陡峭 New Relic ✅ 优势: - APM专业 - 数据可视化好 ❌ 劣势: - 价格高 - 配置复杂

优化策略总结

优化优先级

立即优化 (P0): - Core Web Vitals不达标 - 首屏加载>3秒 - API响应>1秒 - 错误率>1% 计划优化 (P1): - 代码分割未做 - 缓存未使用 - 图片未优化 - 数据库无索引 长期优化 (P2): - 微服务拆分 - 架构重构 - 技术栈升级 - 监控完善

优化检查清单

前端优化: □ 资源压缩 (Gzip/Brotli) □ 图片优化 (WebP/压缩/懒加载) □ 代码分割 □ 缓存设置 □ CDN配置 □ 字体优化 □ 关键资源预加载 □ 减少第三方依赖 后端优化: □ 数据库索引 □ 查询优化 □ 缓存策略 □ 连接池配置 □ 异步处理 □ 负载均衡 □ 监控告警 □ 错误处理 基础设施: □ CDN部署 □ 监控告警 □ 日志收集 □ 自动扩容 □ 健康检查 □ 灾备方案

记住:性能优化是持续的过程,不是一次性任务。定期测量、监控、改进。

Last updated on