性能基础审查 performance-fundamentals

性能基础审查技能用于系统性评估和优化软件应用程序的性能。它涵盖数据库查询优化、前端渲染效率、API响应速度和内存资源管理等方面。通过提供审查清单、常见错误示例和性能目标,帮助开发团队识别性能瓶颈,实施最佳实践,确保应用的可扩展性和用户体验。关键词:性能优化、数据库性能、前端性能、API性能、内存管理、N+1查询、缓存策略。

架构设计 0 次安装 0 次浏览 更新于 3/8/2026

name: performance-fundamentals description: 审查性能,包括N+1查询、重新渲染、可扩展性。当初级开发者问“这性能好吗”、“这能扩展吗”、“太慢了”时使用,或处理循环、大型列表、分页、缓存时使用。

性能基础审查

“过早优化是万恶之源,但成熟的忽视更糟。”

何时应用

在审查以下内容时激活此技能:

  • 数据库查询(尤其是在循环中)
  • React/Vue渲染逻辑
  • API响应负载
  • 数据转换
  • 文件操作
  • 缓存决策

审查清单

数据库性能

  • [ ] 无N+1查询:相关记录是否批量获取,而非循环?
  • [ ] 索引:频繁查询的字段是否已索引?
  • [ ] 分页:列表端点是否对结果进行分页?
  • [ ] 仅选择所需字段:是否不必要地获取整个记录?

前端性能

  • [ ] 记忆化:昂贵的计算是否已缓存?
  • [ ] 防止重新渲染:状态变化是否会导致不必要的重新渲染?
  • [ ] 捆绑包大小:重型库是否懒加载?
  • [ ] 图像优化:图像是否适当调整大小和格式化?

API性能

  • [ ] 响应大小:负载是否最小化?
  • [ ] 压缩:是否启用gzip/brotli?
  • [ ] 缓存头:可缓存响应是否标记?
  • [ ] 异步处理:慢速操作是否已排队?

内存与资源

  • [ ] 清理:订阅/计时器是否已清理?
  • [ ] 内存泄漏:事件监听器是否已移除?
  • [ ] 连接池:数据库连接是否重用?

常见错误(反模式)

1. N+1查询问题

❌ const users = await User.findAll();
   for (const user of users) {
     user.posts = await Post.findByUserId(user.id); // N次查询!
   }

✅ const users = await User.findAll({
     include: [{ model: Post }] // 1次查询,使用JOIN
   });

2. 不必要的重新渲染

❌ function Parent() {
     const handleClick = () => {}; // 每次渲染创建新函数
     return <Child onClick={handleClick} />;
   }

✅ function Parent() {
     const handleClick = useCallback(() => {}, []);
     return <Child onClick={handleClick} />;
   }

3. 在渲染中计算

❌ function UserList({ users }) {
     // 每次渲染都运行
     const sorted = users.sort((a, b) => a.name.localeCompare(b.name));
     return <ul>{sorted.map(...)}</ul>;
   }

✅ function UserList({ users }) {
     const sorted = useMemo(
       () => [...users].sort((a, b) => a.name.localeCompare(b.name)),
       [users]
     );
     return <ul>{sorted.map(...)}</ul>;
   }

4. 获取所有数据

❌ GET /api/users → 返回10,000个用户,包含所有字段

✅ GET /api/users?page=1&limit=20&fields=id,name,email

5. 缺少清理

❌ useEffect(() => {
     const interval = setInterval(fetchData, 5000);
     // 无清理!永远运行。
   }, []);

✅ useEffect(() => {
     const interval = setInterval(fetchData, 5000);
     return () => clearInterval(interval);
   }, []);

苏格拉底式问题

向初级开发者问这些问题,而不是给出答案:

  1. 扩展性:“当有10,000个项目时会发生什么?1,000,000个?”
  2. 查询:“此操作进行了多少次数据库查询?”
  3. 重新渲染:“当此状态改变时,哪些组件会重新渲染?”
  4. 内存:“是否有任何东西在不再需要后仍持有引用?”
  5. 负载:“客户端是否需要所有这些数据?”

Big O 快速参考

模式 复杂度 示例 10,000个项目时
直接查找 O(1) map.get(key) 1次操作
单循环 O(n) array.find() 10,000次操作
嵌套循环 O(n²) for i { for j } 100,000,000次操作
排序 O(n log n) array.sort() ~130,000次操作

性能目标

指标 目标 测量工具
首字节时间 (TTFB) < 600ms DevTools网络
最大内容绘制 (LCP) < 2.5s Lighthouse
首次输入延迟 (FID) < 100ms Lighthouse
累积布局偏移 (CLS) < 0.1 Lighthouse
API响应时间 < 200ms (p95) 服务器指标

需要警惕的红旗

红旗 要问的问题
循环内的查询 “我们能否将其批处理为一次查询?”
无分页 “如果有100,000条记录怎么办?”
SELECT * “我们需要所有这些字段吗?”
localStorage中的大型JSON “这会减慢页面加载吗?”
JSX中的内联函数 “这会在每次渲染时创建新函数吗?”
无清理的setInterval “组件卸载时什么来清除它?”
同步文件操作 “这应该异步吗?”
无加载状态 “用户在等待时看到什么?”

快速改进

  1. 添加索引到频繁查询的数据库列
  2. 分页所有列表端点
  3. 懒加载首屏以下内容
  4. 压缩API响应
  5. 缓存昂贵计算,使用useMemo
  6. 防抖搜索输入
  7. 虚拟化长列表(使用react-window)