SuperAPI AI 工具集

performance-optimization

编程与开发

查看项目

更新于 11-13 16:16

技能介绍

性能优化技能用于在前后端和数据库层面系统地排查与改进应用性能。其核心理念是“先测量再优化”:如果没有测量数据,优化就只是在猜测,容易引入不必要的复杂度。应先做性能剖析、找出真正的瓶颈,再进行修复,然后重新测量。只有在测量证明确实重要时才优化。

适用场景 当规格中存在性能要求(加载时间预算、响应时间 SLA、LCP/INP/CLS 目标);用户或监控报告行为缓慢(高延迟、交互卡顿、jank);Core Web Vitals 分数低于 Good 阈值;怀疑近期改动引入性能回归;构建处理大数据集或高流量的功能;剖析或追踪发现瓶颈;数据获取代码中发现 N+1 查询;打包分析显示存在庞大且不必要的依赖时,可使用本技能。

不适用场景:在获得问题的实证证据前不要优化。过早优化是缺陷、复杂度和无效工作的常见来源。若不确定哪里慢,应先测量。

Core Web Vitals 目标 LCP(最大内容绘制):Good ≤ 2.5 s,Needs Improvement ≤ 4.0 s,Poor > 4.0 s。 INP(交互到下次绘制):Good ≤ 200 ms,Needs Improvement ≤ 500 ms,Poor > 500 ms。 CLS(累积布局偏移):Good ≤ 0.1,Needs Improvement ≤ 0.25,Poor > 0.25。 FCP(首次内容绘制):Good ≤ 1.8 s,Needs Improvement ≤ 3.0 s,Poor > 3.0 s。 TTFB(首字节时间):Good ≤ 800 ms,Needs Improvement ≤ 1.8 s,Poor > 1.8 s。

优化工作流

  1. 测量:用真实数据建立基线(Lighthouse、RUM、EXPLAIN ANALYZE)。
  2. 定位:找出真正的瓶颈,而非假设的瓶颈。
  3. 修复:用针对性改动解决具体瓶颈。
  4. 验证:用与基线相同的方法重新测量。
  5. 防护:添加监控、预算或回归测试。

步骤一:测量,建立基线 使用合成工具做可重复、可控的测量:Lighthouse / PageSpeed Insights(基于实验室的 Core Web Vitals 评分)、Chrome DevTools 的 Performance 面板(火焰图、网络瀑布、打包分析)、WebPageTest(多地点类 RUM 测试与胶片图)、EXPLAIN ANALYZE(数据库查询性能基线)、profile / perf / py-spy(后端进程剖析)。结合真实用户监控(RUM)捕获真实环境:web-vitals 库报告实时 LCP、INP、CLS;CrUX 提供真实 Chrome 用户的聚合字段数据;APM 工具(Datadog、New Relic、Sentry)提供后端延迟分布。记录基线数值,没有具体的前值就无法判断优化是否生效。

步骤二:定位,找出实际瓶颈 按症状诊断:LCP 慢通常因为图片过大、渲染阻塞资源、服务端响应慢,使用 Lighthouse、网络瀑布诊断;CLS 高通常因为图片缺少尺寸、广告/字体晚加载、动态嵌入,使用 Lighthouse CLS 诊断、布局偏移追踪;INP 差通常因为长任务(重 JS)、DOM 过大、事件处理慢,使用 Performance 面板、Long Tasks API;打包体积大通常因为未使用依赖、缺少代码分割、模块重复,使用 vite-bundle-analyzer、webpack-bundle-analyzer;N+1 查询通常因为循环中的 ORM 懒加载,使用 EXPLAIN ANALYZE、Rails/ActiveRecord 日志、Django Debug Toolbar;API 响应慢通常因为缺少索引、低效 join、连接池耗尽,使用 EXPLAIN ANALYZE、连接池指标;内存高通常因为无界缓存、内存泄漏、大数据集驻留内存,使用堆快照、malloc 剖析。

步骤三:修复,针对反模式 每个修复都必须由步骤二的数据支撑,而非直觉。 前端:图片相对显示尺寸过大 → 使用 <picture> / srcset 响应式断点,提供 WebP/AVIF;渲染阻塞的 CSS/JS → 内联关键 CSS,用 type="module" 或 defer 延迟非关键 JS;缺少图片尺寸 → 始终设置 width 和 height 预留布局空间;客户端 JS 过重 → 按路由用 dynamic import() 代码分割,tree-shake 未使用导出;React 不必要的重渲染 → React.memo、useMemo、useCallback,保持 props 引用稳定;字体加载导致 CLS → font-display: swap 或 optional 配合 size-adjust;大型第三方脚本 → 异步加载,非关键则延迟,评估移除。 后端:N+1 查询 → 预加载(joins、includes),在单次查询中批量获取;无界数据获取 → 使用游标或偏移分页限制;缺少数据库索引 → 按查询模式添加复合索引,用 EXPLAIN 验证;连接池耗尽 → 调整池大小(max_connections),加入 PgBouncer 或代理多路复用;无缓存 → 添加 HTTP 缓存头,对昂贵且冷的数据加应用层缓存;序列化过大响应 → 只投影所需字段,使用分页与流式传输。 数据库:大表全表扫描 → 添加索引、重写查询以使用索引、分区表;JOIN 顺序低效 → 重构查询以先过滤选择性最高的条件;过度取列 → SELECT * 改为 SELECT 所需列;加索引前未检查查询计划 → 始终在加索引前后运行 EXPLAIN (ANALYZE, BUFFERS)。

步骤四:验证,用相同方式复测 运行完全相同的测量(同工具、同页面、同位置);与基线数值比较;若改动未改善指标则回退;若改善一个指标却回退另一个,按 SLA 优先级决定。

步骤五:防护,防止回归 在 Lighthouse CI 中设置性能预算(如“LCP 必须保持在 2.5s 以下”),超出预算的 PR 构建失败;用 bundlewatch 等工具比较 PR 打包体积差异;自定义 RUM 仪表盘监控关键指标的 P75、P95、P99;部署前对慢查询运行 EXPLAIN ANALYZE 作为数据库迁移防护。

常见合理化借口及现实 “以后再优化” → 性能债会累积,现在就修复明显的反模式。 “我机器上很快” → 要在具代表性的硬件和限速网络上剖析,开发机不等于生产。 “这个优化显而易见” → 没测量就不知道,假设错误率超过 50%。 “查询慢,加索引” → 先读查询计划,索引可能已失效或问题另有原因。 “缓存一下就行” → 只缓存计算昂贵且读取远多于写入的数据,永不命中的缓存是负担。 “CDN 能解决速度” → CDN 改善全球用户 TTFB,但不修复臃肿打包、N+1、布局偏移。 “全部懒加载” → 过度懒加载会延迟交互,首屏关键内容应尽早加载。 “用某框架重写” → 框架重写是最昂贵的性能“修复”,先剖析,针对性改动成本低几个数量级。 “Lighthouse 过了就行” → Lighthouse 是合成实验室测试,真实用户条件(2G、老设备、广告拦截)不同,需用 RUM 验证。

危险信号 没有剖析数据就做优化;新增或修改的数据获取代码出现 N+1;加索引前后未审查查询计划;缓存实现未说明过期窗口或淘汰策略;列表端点无分页或 LIMIT 无界;图片渲染未指定宽高;优化未经复测确认就留在生产;基于单次测量声称性能提升(方差真实存在,应平均 3 次以上);无剖析证据就提出框架迁移作为性能修复。

验证清单 前后测量有具体数值(不是“感觉更快”);用与基线相同工具/方法复测;未明显超过基线方差的改动已回退;优化页面 Core Web Vitals 处于 Good 阈值;新增或修改的数据获取代码无 N+1;每个新索引都有查询计划支撑(前后 EXPLAIN ANALYZE);缓存实现记录缓存内容、TTL/过期、最大容量、淘汰策略;所有分页端点有界并记录游标/偏移;图片有显式宽高与响应式格式;打包体积已验证,相对基线无意外增长;优化后既有功能测试仍通过;RUM 数据确认实验室改进在真实环境成立。

参考资料 references/browser-performance-metrics.md:Core Web Vitals 详细诊断与工具;references/query-optimization.md:数据库查询剖析与索引设计指南;references/image-optimization-guidelines.md:响应式图片、格式选择、懒加载。