十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Cherry Studio 规则实践解读:合并多次数组遍历的 JS 性能优化(js-combine-iterations)

Cherry Studio 规则实践解读:合并多次数组遍历的 JS 性能优化(js-combine-iterations) Cherry Studio 规则实践解读合并多次数组遍历的 JS 性能优化js-combine-iterations【免费下载链接】cherry-studio Cherry Studio 是一款支持多个 LLM 提供商的桌面客户端项目地址: https://gitcode.com/CherryHQ/cherry-studio在 Cherry Studio 仓库的.agents/skills/目录下内置了一套源自 Vercel 工程实践的 React/Next.js 性能优化规则集其中js-combine-iterations规则针对一个高频反模式对同一个数组连续调用多次.filter()或.map()导致数组被重复遍历。本文完整解析该规则的问题本质、正确写法与适用边界并结合仓库中的技能定义文件SKILL.md、README.md与编译产物AGENTS.md说明这条规则在整套规则体系中的定位、编写规范与使用方式。规则定位JavaScript Performance 类别中的第 7.6 条该规则的源文件是 js-combine-iterations.md其 frontmatter 元数据如下字段值含义titleCombine Multiple Array Iterations规则标题impactLOW-MEDIUM影响级别低-中属于渐进式收益impactDescriptionreduces iterations收益来源减少遍历次数tagsjavascript, arrays, loops, performance检索标签JS、数组、循环、性能在整套技能中规则按影响程度分为 8 个优先级类别见 SKILL.md 的 Rule Categories by Priority。本规则属于第 7 类JavaScript Performance前缀js-整体影响级别 LOW-MEDIUM优先级第 7与消除瀑布流async-CRITICAL、包体积优化bundle-CRITICAL等高优先级类别相比它处理的是纯 JS 层面的微优化。编译后的 AGENTS.md 目录将其编号为7.6 Combine Multiple Array Iterations同章节还有 7.7 Early Length Check、7.10 flatMap 单遍转换等邻近规则。规则详解把 N 次遍历合并为 1 次问题描述原文规则的核心陈述只有两句多个.filter()或.map()调用会多次遍历数组应把它们合并进一个循环。每一个链式或并列的数组高阶函数调用都会对原数组完整走一遍迭代。当同一段代码针对同一数组发起多个筛选/映射请求时遍历次数就是调用次数的线性叠加。以规则中的反例为例三次独立遍历// 错误写法同一个 users 数组被完整遍历 3 次 const admins users.filter(u u.isAdmin) const testers users.filter(u u.isTester) const inactive users.filter(u !u.isActive)三个结果集相互独立但数据源是同一个users数组。运行时的实际开销是 3N 次元素访问外加 3 个中间数组的分配。正确写法单次遍历 条件分桶规则给出的正确写法是单循环多目标模式先声明各个目标数组在一次for...of遍历中根据条件把元素推入对应的桶// 正确写法只遍历 1 次一次循环产出 3 个结果集 const admins: User[] [] const testers: User[] [] const inactive: User[] [] for (const user of users) { if (user.isAdmin) admins.push(user) if (user.isTester) testers.push(user) if (!user.isActive) inactive.push(user) }两个实现细节值得注意显式类型标注。合并后需要手工声明每个结果数组const admins: User[] []因为.filter()会自动推导类型而空数组[]会被推断为never[]缺少标注在 TypeScript 下会直接报错。规则示例特意保留了这些标注这正是合并写法需要付出的类型成本。各分支相互独立。注意三个if不是if/else if链——一个用户完全可能既是isAdmin又是!isActive会被同时推入两个桶语义与三个独立.filter()完全一致。若误用else if就会改变原逻辑的语义。收益与适用边界的分析从复杂度看两种写法都是 O(N)但常数项差异明确元素访问与条件求值次数从 3N 降到 N中间结果只保留最终需要的数组反例中每个.filter()各自产生的分配模式不变但遍历调度函数调用、闭包求值开销减少两次。该规则被定为LOW-MEDIUM影响级别隐含的判断是它属于值得做但不是最优先的优化。可以推断出实践上的适用边界值得做数组规模大成百上千以上、处于热路径渲染循环、高频事件处理、批量数据导入导出不值得做数组只有个位数元素或筛选条件之间逻辑复杂、合并后单个循环体变得难以审查——此时三次独立.filter()的声明式可读性更优。这一点也与整套规则的优先级设计一致在 SKILL.md 中消除瀑布流和包体积被列为 CRITICAL而本条只排到第 7 优先级提示开发者先解决结构性问题再做循环层面的微调。同族规则JavaScript Performance 类别全景本规则不是孤立的。按 SKILL.md 的快速参考表第 7 类js-规则共 13 条共同目标是减少 JS 执行中的冗余工作与查找开销规则文件要点js-batch-dom-css通过 class 或cssText批量提交 CSS 变更避免样式重算js-index-maps为重复查找构建索引 Mapjs-cache-property-access循环内缓存对象属性访问js-cache-function-results用模块级 Map 缓存函数结果js-cache-storage缓存 localStorage/sessionStorage 读取js-combine-iterations合并多个 filter/map 为一次循环本文规则js-length-check-first昂贵比较前先检查数组长度js-early-exit函数内提前返回js-hoist-regexpRegExp 创建提升到循环外js-min-max-loop用循环求 min/max 代替排序js-set-map-lookups用 Set/Map 实现 O(1) 查找js-tosorted-immutable用toSorted()代替sort()保持不可变js-flatmap-filter用 flatMap 单遍完成映射过滤其中最常与本规则配合判断的是 js-flatmap-filter.md。两条规则解决的是多次遍历这一同族问题的不同形态js-combine-iterations多个结果集、每个结果集都是原数组的某种筛选 → 用单循环分桶js-flatmap-filter一个结果集但需要先变换再过滤.map().filter(Boolean)链会产生中间数组并遍历两次 → 用flatMap单遍完成。// flatMap 规则的反例2 次遍历 中间数组 const userNames users .map(user user.isActive ? user.name : null) .filter(Boolean) // flatMap 规则的正确写法1 次遍历、无中间数组 const userNames users.flatMap(user user.isActive ? [user.name] : [] )选型口诀可以概括为多桶分流出多个数组走合并循环变换后再过滤出一个数组走flatMap。规则文件的编写规范frontmatter、影响级别与构建流程这套技能的价值不仅在于单条规则还在于它定义了机器可读的规则格式使 Agent/LLM 可以批量检索和应用。了解这套规范有助于理解js-combine-iterations.md每个字段的用途。按 README.md 的说明规则库的目录结构为rules/— 单条规则文件每条一个 md 文件AGENTS.md— 由规则编译生成的完整文档本仓库中即 AGENTS.md含自动编号的目录与全部规则展开test-cases.json— 为 LLM 评估提取的测试用例生成物。每个规则文件必须遵循固定骨架YAML frontmattertitle、impact、impactDescription、tags 简短的问题陈述 Incorrect 代码块带错误原因标注Correct 代码块带正确原因标注 可选的补充说明。js-combine-iterations.md正是这一骨架的标准实例。文件命名约定文件名采用前缀-描述.md格式前缀决定章节归属例如js-对应 JavaScript Performance第 7 节、async-对应 Eliminating Waterfalls第 1 节下划线开头的文件如_template.md是特殊文件不参与构建章节内规则按标题字母序自动排序编号7.6 之类在构建时自动生成无需手工维护。影响级别共 6 档从高到低CRITICAL最大收益、HIGH、MEDIUM-HIGH、MEDIUM、LOW-MEDIUM低-中收益、LOW渐进式改进。本规则取LOW-MEDIUM并在impactDescription中补充了收益来源 reduces iterations这在编译产物中会呈现为 Impact: LOW-MEDIUM (reduces iterations)见 AGENTS.md 7.6 节。构建与维护命令由 README 定义适用于按此规范新建的规则库pnpm install # 安装依赖 pnpm build # 从 rules/ 编译生成 AGENTS.md 与 test-cases.json pnpm validate # 校验所有规则文件 pnpm extract-tests # 提取 LLM 评估测试用例 pnpm dev # build validate在 Cherry Studio 仓库中如何使用该技能结合 SKILL.md 的 When to Apply 一节该技能在 Cherry Studio 仓库中的定位是Agent/开发者的 React 代码编写参考触发场景包括编写新的 React 组件或 Next.js 页面实现数据获取客户端或服务端评审代码时排查性能问题重构既有 React 代码优化包体积或加载时间。具体到js-combine-iterations这条规则实际用法是当在评审或重构 src/renderer/ 下的大量 TSX/TS 代码聊天列表、资源目录、消息处理等含数组筛选逻辑的模块时如果发现同一数组被连续多次.filter()/.map()即可按上述单循环多目标模式重写。技能要求每条规则文件给出解释 错误示例 正确示例 上下文参考四要素目的正是让 Agent 能直接检索单条规则文件rules/js-combine-iterations.md并照搬模式而不必读完全量文档。此外该技能的存在也被仓库自身的功能所索引技能名称 vercel-react-best-practices 出现在技能搜索功能的测试夹具中skillSearch.test.ts 及其 fixtures 目录下的 JSON 文件说明仓库的技能发现机制会把它纳入可搜索范围。落地检查清单将本规则应用到一次实际重构时可以按以下清单执行识别模式同一段作用域内是否对同一数组发起了 2 次及以上的.filter()/.map()且各次调用的数据源未变化确认结果集形态多个相互独立的筛选结果 → 单循环分桶变换后过滤出单个结果 → 改用flatMap参考 js-flatmap-filter.md保持语义分桶分支用独立if而非if/else if除非原逻辑本就互斥为每个结果数组补上显式类型标注评估收益档位确认数组规模与调用频率足以让 LOW-MEDIUM 级别的优化产生可感知收益否则保留声明式写法以换取可读性回归验证按仓库根 AGENTS.md 的开发约定运行pnpm lint含 format typecheck i18n 检查并执行覆盖改动模块的测试如pnpm exec vitest run 文件确认行为一致。规则原文虽短但减少无谓遍历的思想是普适的它既是一条可被 Agent 精确检索执行的重构指令也是人工代码评审时判断这段数组操作是否可以更省的快速标尺。在 Cherry Studio 这样以 Electron React 大型渲染层为主要代码构成、且内置了完整 Agent 技能体系的仓库中这类结构化规则显著降低了性能优化知识的传递成本。【免费下载链接】cherry-studio Cherry Studio 是一款支持多个 LLM 提供商的桌面客户端项目地址: https://gitcode.com/CherryHQ/cherry-studio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表