mcpField
A
accelint-ts-performance

accelint-ts-performance

github.com/gohypergiant开发25344 次安装2 周前更新
代码仓库

关于 accelint-ts-performance

用于系统审查和优化 JavaScript/TypeScript 性能的技能,指导分析瓶颈与反模式,并提供优化方法和正确性检查流程。

主要功能

  1. 01系统化性能审查
  2. 02识别算法效率问题
  3. 03评估 CPU 与内存取舍
  4. 04按问题类别应用优化模式
  5. 05变更后验证正确性

适用场景

  1. 01审查 JavaScript 代码库性能
  2. 02查找低效循环和查找操作
  3. 03优化内存或 I/O 行为

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/gohypergiant/agent-skills --skill accelint-ts-performance

安装后在 Claude Code 中输入/accelint-ts-performance确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

AGENTS.md
README.md
assets/
output-report-template.md
references/
avoid-allocations.md
batching.md
bounded-iteration.md
cache-property-access.md
cache-storage-api.md
currying.md
defer-await.md
memoization.md
object-operations.md
performance-misc.md
predictable-execution.md
quick-reference.md
reduce-branching.md
reduce-looping.md

详细介绍

TypeScript 性能优化

针对 JavaScript/TypeScript 代码库的系统性性能优化。结合审计工作流与专家级优化模式,提升运行时性能。

性能优化时绝对不要做的事

注意: 对于通用最佳实践(例如使用 any/enum 保证类型安全、避免使用 null、不要修改参数),请改用 accelint-ts-best-practices 技能。本节仅关注性能相关的反模式。

  • 绝不要假定代码属于冷路径——工具函数、格式化器、解析器和验证器看起来简单,但经常会在循环、渲染管线或实时系统中被调用。务必审计所有代码,检查是否存在性能反模式。不要臆测代码的使用频率,也不要因其看似简单而跳过审计。

  • 绝不要盲目应用所有优化——性能模式各有取舍。应在优化收益与代码复杂度之间取得平衡。开展审计时,应通过系统性分析识别所有反模式,并报告预期收益。由用户根据具体情况决定采用哪些优化。

  • 绝不要忽视算法复杂度——对 O(n²) 代码进行微优化无济于事。对于 n=1000,算法层面的修复(O(n² → O(n))可带来 1000 倍加速;微优化最多只能达到 1.1–2 倍。先修复算法:使用 Maps/Sets 实现 O(1) 查找、消除嵌套迭代,并选择合适的数据结构。

  • 绝不要为了速度牺牲正确性——性能问题依然是问题。优化经常会破坏边界情况:手动循环中的差一错误、空数组行为错误、null 处理问题。请验证优化前后的行为一致。优化前应添加涵盖边界情况的全面测试——在生产环境中发现 Bug 的代价远高于任何性能收益。

  • 绝不要优化你不负责的代码——共享工具、库的内部实现,或他人正在积极开发的代码,可能引发合并冲突、重复劳动和归属混乱。性能改动会影响所有调用方;应与负责人协调,或等代码稳定后再进行优化。

  • 绝不要忽视内存与 CPU 之间的权衡——缓存以空间换速度。在长时间运行的应用中,无界记忆化会导致内存泄漏。如果 CPU 提速 2 倍却让内存使用量增加 10 倍,可能导致 OOM 崩溃或频繁的 GC 暂停(比原本的慢更糟)。应同时分析内存和 CPU 使用情况;限制缓存大小;对于生命周期受限的缓存,使用 WeakMap。

  • 绝不要假定优化在所有环境中都有效——V8 优化在不同 Node.js 版本(v18 与 v20)、浏览器(Chrome 与 Safari)和架构(x64 与 ARM)之间有所不同。在 Chrome 中可提速 3 倍的优化,在 Safari 中可能导致性能下降 1.5 倍。发布前应在所有目标环境中进行性能分析;针对特定环境的优化应保留回退实现。

  • 绝不要链式调用数组方法(.filter().map().reduce())——每个方法都会创建中间数组并单独遍历。对于包含 10k 个元素的数组,.filter().map() 会分配 10k + 5k 个元素(若 50% 通过筛选),并遍历两次。使用单次 reduce 遍历,一次完成操作且不产生中间分配,可在热点路径中提速 2–5 倍。

  • 绝不要在重复查找时使用 Array.includes()——Array.includes() 是 O(n) 线性搜索。对数组中的 100 个元素逐一检查 1000 个项目,复杂度为 O(n×m) = 100k 次操作。改用 Set.has():通过哈希表实现 O(1) 查找,可将 100k 次操作降至 1000 次,提速约 100 倍。提前构建一次 Set;其摊销成本可以忽略。

  • 永远不要在确认是否需要结果之前就使用 await——await 会立即暂停执行,即使你并不需要该值。将 await 移到实际需要结果的条件分支中。例如:const data = await fetch(url); if (condition) { use(data); } 在 condition 为 false 时会浪费 I/O 时间。更好的做法是:if (condition) { const data = await fetch(url); use(data); },这样在不需要时就会跳过 fetch。

  • 永远不要在循环中重新计算常量——每次迭代都重新计算不变量会浪费 CPU。循环 10k 次时,array.length 查询(即使引擎会缓存)或 Math.max(a, b) 都会无谓地运行 10k 次。将不变量提到循环外:const len = array.length; for (let i = 0; i < len; i++),或使用柯里化函数,只预先计算一次常量参数。

  • 永远不要创建无界循环或队列——这可以防止错误或恶意输入导致资源消耗失控。设置明确的限制(for (let i = 0; i < Math.min(items.length, 10000); i++))或超时。无界循环可能会冻结 UI 线程;无界队列会导致 OOM 崩溃。应设置清晰的限制并快速失败,而不是逐渐退化到无法使用。

  • 永远不要在热点路径中使用 try/catch——V8 无法内联包含 try-catch 块的函数,并会将整个函数标记为不可优化。在热点循环中使用单个 try-catch,就会因阻止内联、逃逸分析和其他优化而导致性能降低 3-5 倍。应在进入热点路径前使用类型守卫验证输入;将 try-catch 移到循环外以包裹整个操作;对预期错误使用 Result 类型。

优化性能前,请先思考

应用以下检查,以有效地集中优化工作:

影响评估
  • 这段代码真的慢吗? 有性能分析数据时,应据此确定优先级。没有数据时,应审查所有代码,找出反模式。
  • 它占运行时间的百分之几? 有性能分析数据时,火焰图有助于找出影响最大的问题。没有数据时,应报告发现的所有反模式。
  • 原始性能很重要——无论当前使用场景如何,都应审查所有代码中的性能反模式。即使工具函数、格式化器、解析器和数据转换看起来很简单,也经常会在循环、渲染流水线或实时系统中被调用。
正确性验证
  • 我有覆盖这段代码的测试吗? 性能问题往往很隐蔽。全面的测试可以发现优化导致的回归。优化前应添加测试。
  • 有哪些边界情况? 手动优化循环时,更容易出现差一错误、空数组以及 null/undefined 值等问题。应进行全面测试。
复杂度与收益
  • 算法复杂度是否已达到最优? O(n) → O(1) 可带来 1000 倍的加速。微优化最多只能带来 1.1-2 倍的提升。应先改进算法。
  • 这项优化会长期有效吗? 如果代码经常变更,优化可能很快就会被舍弃。应先优化稳定的代码。
  • 可读性会受到多大影响? 手动循环比 .map() 快,但也更难维护。应在性能与团队效率之间取得平衡。

使用方法

此技能采用渐进式披露,以尽量减少上下文占用:

1. 从工作流开始(SKILL.md)

按照下方的 4 阶段审查工作流,系统地分析性能。

2. 参考性能规则概览(AGENTS.md)

加载 AGENTS.md,浏览按类别整理的精简规则摘要。

3. 按需加载具体的性能模式

发现具体的性能问题时,加载相应的参考文件,查看详细的 ❌/✅ 示例。

4. 使用报告模板(针对明确的审查请求)

用户明确要求进行性能审查时,加载模板,以便生成格式一致的报告:

性能优化工作流

两种运行模式:

  1. 审计模式——直接调用技能(/accelint-ts-performance <path>)或用户明确请求性能审计

    • 使用模板生成结构化审计报告(仅限阶段 1–2)
    • 在实施前报告发现的问题,供用户审阅
    • 由用户决定应用哪些优化
  2. 实施模式——在功能开发过程中自动触发技能

    • 直接识别并应用优化(全部 4 个阶段)
    • 无需正式报告
    • 专注于就地修复问题

复制此清单以跟踪进度:

- [ ] Phase 1: Profile - Identify actual bottlenecks using profiling tools
- [ ] Phase 2: Analyze - Categorize issues by impact and optimization category
- [ ] Phase 3: Optimize - Apply performance patterns from references/
- [ ] Phase 4: Verify - Measure improvements and validate correctness
阶段 1:分析性能,识别瓶颈

重要:审查所有代码中的性能反模式。 不要根据对使用频率的假设跳过代码。即使工具函数、格式化器、解析器、验证器和数据转换的实现看起来很简单,它们也经常会在循环、渲染管线或实时系统中被调用。

如果有可用的性能分析工具,请使用它们建立基准测量:

  • 浏览器:Chrome DevTools 的 Performance 标签页
  • Node.js:node --prof script.js && node --prof-process isolate-*.log

无论是否有性能分析数据:都要对代码进行系统性静态分析,以识别所有性能反模式:

  • O(n²) 复杂度(嵌套循环、重复搜索)
  • 过度分配(模板字面量、对象展开、数组方法)
  • 在使用 String() 即可满足需求时分配模板字面量
  • 链式调用数组方法(.filter().map())
  • 阻塞异步操作
  • 循环中的 try/catch

输出:列出所有已识别反模式及其位置和预期性能影响。不要按“严重程度”或“优先级”筛选——报告发现的所有问题。

生成审计报告时(直接通过 /accelint-ts-performance <path> 调用技能,或用户明确请求性能审计时),请使用结构化模板:

  1. 加载 assets/output-report-template.md,了解报告结构
  2. 按照模板的说明统一格式并对问题分组
阶段 2:分析并分类问题

对阶段 1 中识别的每个问题,按优化类型进行分类:

按优化类型对所有问题进行分类:

问题类型类别预期提升
嵌套循环、O(n²) 复杂度算法优化10-1000x
重复执行高开销计算缓存与记忆化2-100x
分配密集型代码减少分配1.5-5x
违反顺序访问原则内存局部性1.5-3x
过多 I/O 操作I/O 优化5-50x
阻塞异步操作I/O 优化2-10x
循环中的属性访问缓存与记忆化1.2-2x

问题映射速查:

加载 references/quick-reference.md,查看详细的问题到类别映射和反模式检测说明。

输出: 列出所有问题及其优化类别。不要筛选或排序优先级——列出阶段 1 中发现的所有问题。

阶段 3:使用性能模式进行优化

步骤 1: 根据阶段 2 的分析,确定瓶颈类别。

步骤 2: 加载对应类别的必读参考资料。完整阅读每个文件,不限制范围。

类别必读文件可选不要加载
算法(O(n²)、嵌套循环、重复查找)reduce-looping.md
reduce-branching.md
—memoization、caching、I/O、allocation
缓存(循环中的属性访问、重复计算)memoization.md
cache-property-access.md
cache-storage-api.md(适用于 Storage API)I/O、allocation
I/O(阻塞异步操作、过多 I/O 操作)batching.md
defer-await.md
—algorithmic、memory
内存(分配密集、GC 压力)object-operations.md
avoid-allocations.md
—I/O、caching
局部性(违反顺序访问、缓存未命中)predictable-execution.md—所有其他文件
安全性(无界循环、队列失控)bounded-iteration.md—所有其他文件
微优化(热路径微调、1.1-2 倍提升)currying.md
performance-misc.md
—所有其他文件(仅在完成算法优化后应用)

注意:

  • 如果瓶颈涉及多个类别,请加载所有相关类别的参考资料
  • 仅在以下条件都满足时应用微优化:瓶颈位于热路径中、已完成算法优化、还需要额外的 1.1-2 倍性能提升

步骤 3:优化期间查阅快速参考

加载 AGENTS.md,查看按类别整理的精简规则摘要。在根据上述详细参考文件应用模式时,可将其用作快速查阅资料。

系统地应用模式:

  1. 加载参考文件,了解已识别问题所属类别
  2. 浏览 ❌/✅ 示例,寻找匹配的模式
  3. 应用优化,尽量减少改动以保证正确性
  4. 添加注释,说明优化内容并引用对应模式

优化示例:

// ❌ Before: O(n²) - nested iteration
for (const user of users) {
  const items = allItems.filter(item => item.userId === user.id);
  process(items);
}

// ✅ After: O(n) - single pass with Map lookup
// Performance: reduce-looping.md - build lookup once pattern
const itemsByUser = new Map<string, Item[]>();
for (const item of allItems) {
  if (!itemsByUser.has(item.userId)) {
    itemsByUser.set(item.userId, []);
  }
  itemsByUser.get(item.userId)!.push(item);
}

for (const user of users) {
  const items = itemsByUser.get(user.id) ?? [];
  process(items);
}
阶段 4:验证改进效果

衡量性能提升:

  1. 使用相同输入重新运行性能分析器
  2. 比较优化前后的运行时间百分比
  3. 记录加速倍数(例如:“快 2.3 倍”)

验证正确性:

  1. 运行现有测试套件——所有测试都必须通过
  2. 针对受优化影响的边界情况添加新测试
  3. 对面向用户的功能进行手动测试

记录优化:

// Performance optimization applied: 2026-01-28
// Issue: Nested iteration causing O(n²) complexity with 10k items
// Pattern: reduce-looping.md - Map-based lookup
// Speedup: 145x faster (5200ms → 36ms)
// Verified: All tests pass, manual QA complete

决定是否保留优化:

  • 提速 >10 倍: 只要测试通过,就始终保留
  • 提速 2-10 倍: 如果测试通过且代码仍易于维护,则保留
  • 提速 1.2-2 倍: 对热路径(每秒执行次数 >1000)或实时系统予以保留
  • 提速 1.05-1.2 倍: 仅当改动微不足道,或涉及关键渲染/动画循环时保留
  • 提速 <1.05 倍: 回退,除非可读性也有所提升

实时系统(60fps 渲染、实时数据可视化): 即使是 1.05 倍的提升,在关键热路径中也有意义。使用帧时间分析器验证其对帧预算的影响(60fps 下为 16.67ms)。

如果测试失败: 修复优化或回退。性能问题也是问题。

自由度校准

根据优化带来的影响校准指导的具体程度:

优化类型自由度指导形式示例
算法(提升 10 倍以上)中等自由度提供多种有效方案,根据约束条件选择“使用 Map 实现 O(1) 查找,或使用 Set 去重”
缓存(提升 2–10 倍)中等自由度提供带示例的模式和缓存失效策略“如果生命周期与源对象一致,则使用 WeakMap 进行记忆化”
微优化(提升 1.1–2 倍)低自由度使用参考资料中的确切模式,先进行测量“在循环中缓存 array.length:for (let i = 0, len = arr.length; ...)”

判断标准:“能提速多少,维护成本又是多少?”

  • 提速 10 倍以上 → 值得增加复杂度,采用中等自由度并提供模式
  • 提速 2–10 倍 → 用测量结果证明其合理性,采用中等自由度
  • 提速 1.2–2 倍 → 对热点路径和实时系统很有价值,采用低自由度并使用确切模式
  • 提速 1.05–1.2 倍 → 仅在改动极其简单或属于关键热点路径(60fps 渲染等)时采用

重要说明

  • 全面审计理念——审计所有代码,查找性能反模式。即使实用函数、格式化器、解析器和验证器看起来很简单,它们也常常在循环或实时系统中被频繁调用。不要假设它们的使用频率。
  • 报告所有发现——无论是否有性能分析数据,都要进行系统化静态分析,找出并报告所有反模式及其预期收益。不要根据“严重程度”或“优先级”进行筛选。
  • 参考文件具有权威性——references/ 中的模式均已验证。除非测量结果证明另有更优方案,否则请严格遵循。
  • 热点路径的定义——每次用户交互执行超过 1000 次,或在服务端场景中每秒执行超过 100 次的代码。对于实时系统(60fps 渲染、实时可视化),热点路径是指关键渲染循环中每帧耗时超过 1ms 的函数。
  • 实时系统有更严格的要求——60fps 的帧预算为 16.67ms,120fps 的帧预算为 8.33ms。热点路径即使提升 1.05 倍也很有价值。应使用帧耗时进行性能分析,而不只是总执行时间。
  • 回归测试——性能优化经常会在边缘情况下引入细微错误。优化前应添加测试。
  • 内存性能分析很重要——某些优化(记忆化、缓存)会以占用内存换取速度。应在生产环境中监控内存使用量,尤其是长时间运行的实时应用。

快速决策树

使用此表快速确定适用的优化类别。

全面审查:无论代码当前的使用场景如何,都要识别其中的所有性能反模式。报告所有发现并说明预期收益。

如果你看到……根本原因优化类别预期收益
对同一数据进行嵌套 for 循环O(n²) 复杂度算法优化(减少循环)10-1000 倍
先调用 .filter(),再调用 .find() 或 .map()多次遍历数据算法优化(减少循环)2-10 倍
重复调用 array.find() 或 .includes()O(n) 线性搜索算法优化(减少循环,使用 Set/Map)10-100 倍
对同一变量使用大量 if/else 分支分支密集型代码算法优化(减少分支)1.5-3 倍
多次使用相同参数调用同一函数重复计算缓存(记忆化)2-100 倍
在循环中多次访问 obj.prop.nested.deep属性访问开销缓存(缓存属性访问)1.2-2 倍
在循环中调用 localStorage.getItem() 或访问 sessionStorage循环中的高开销 I/OI/O(批处理,延迟 await)5-20 倍
按顺序多次调用 await fetch()顺序 I/O 阻塞I/O(批处理,延迟 await)2-10 倍
在可能不需要结果的条件判断之前使用 await过早挂起异步操作I/O(延迟 await)1.5-3 倍
大量使用对象展开 {...obj} 或数组展开 [...arr]分配开销内存(避免分配)1.5-5 倍
在热点循环中创建对象或数组分配导致 GC 压力内存(避免分配)2-5 倍
在可以安全修改对象时使用 Object.assign() 或展开语法不必要的不可变性开销内存(对象操作)1.5-3 倍
非连续访问数组元素缓存局部性问题内存局部性(可预测执行)1.5-3 倍
使用 while(true) 或让队列无限增长资源使用失控安全性(限制迭代次数)防止崩溃
调用函数时前 N 个参数大多相同重复传递参数微优化(柯里化)1.1-1.5 倍
在热点循环中使用 try/catchV8 反优化微优化(其他性能优化)3-5 倍
在循环中使用 + 拼接字符串字符串复制呈二次方增长微优化(其他性能优化)2-10 倍

如何使用此表:

  1. 根据性能分析器发现的瓶颈识别模式
  2. 在“如果你看到……”列中查找对应行
  3. 跳转到第 3 阶段中对应的优化类别
  4. 加载该类别的必需参考文件

评论

支持 Markdown