人工智能大模型代码智能体AI Agent桌面应用后端前端CLI【免费下载链接】ZCodeZCode 是 AI 编程工作台提供桌面应用、浏览器界面和终端 Agent。本仓库包含客户端、后端服务、共享 UI以及 Agent CLI 与运行时源码。项目地址https://gitcode.com/zai-org/ZCode点击查看免费下载ZCode智谱 AI 编程工作台前端采用 React/TypeScript 技术栈其仓库内置了源自 Vercel 工程团队的 React/Next.js 性能优化规则集.agents/skills/react-best-practices用于指导自动化代码生成与重构。本文聚焦其中 JavaScript 性能类别下的js-cache-function-results规则当同一函数在渲染期间以相同入参被反复调用时用模块级 Map 缓存计算结果memoization。读完本文你将掌握模块级缓存的标准写法、单值函数的简化模式、缓存失效策略以及它在 ZCode 仓库如代码高亮模块中的真实落地形态。规则背景这条规则从哪来、优先级如何js-cache-function-results是 ZCode 仓库中 vendored 的 react-best-practices 技能 下的 70 条规则之一。该技能将规则按影响优先级分为 8 类本文主题属于第 7 类JavaScript PerformanceLOW-MEDIUM 优先级前缀为js-优先级类别Impact前缀7JavaScript PerformanceLOW-MEDIUMjs-单条规则文件的 frontmatter 声明了它的元信息title: Cache Repeated Function Callsimpact: MEDIUMimpactDescription: avoid redundant computation避免冗余计算tags: javascript, cache, memoization, performance在完整编译版 AGENTS.md 中它位于7.4 Cache Repeated Function Calls小节。规则的适用场景是writing, reviewing, or refactoring React/Next.js code——即编写新组件、审查代码或做性能重构时应主动检查是否存在相同入参的重复函数调用。问题场景渲染期对相同输入反复调用纯函数规则给出的反面示例是一段典型的 React 列表渲染代码ProjectList组件对每个 project 调用一次slugify()来生成 slug但项目列表可能包含大量重名项目导致同一名称被重复计算上百次function ProjectList({ projects }: { projects: Project[] }) { return ( div {projects.map(project { // slugify() called 100 times for same project names const slug slugify(project.name) return ProjectCard key{project.id} slug{slug} / })} /div ) }这里的核心问题是slugify是纯函数相同输入必然产生相同输出但每次渲染都重新执行一遍。当列表规模大、函数计算成本高例如字符串处理、正则替换、编码转换时这部分开销会随渲染次数线性放大——每次 state 变化触发重渲染整个列表都要重新计算一遍。判断是否值得缓存的三个条件函数是确定性的相同输入 → 相同输出如slugify、正则替换、JSON.stringify格式化同一输入在多次渲染周期内反复出现单次计算成本可观不是简单的算术或属性读取。满足以上条件时缓存收益显著否则引入缓存反而是过早优化。解决方案模块级 Map 缓存规则给出的正确写法是把缓存提升到模块作用域用一个Mapstring, string记录已计算过的输入-输出对// Module-level cache const slugifyCache new Mapstring, string() function cachedSlugify(text: string): string { if (slugifyCache.has(text)) { return slugifyCache.get(text)! } const result slugify(text) slugifyCache.set(text, result) return result } function ProjectList({ projects }: { projects: Project[] }) { return ( div {projects.map(project { // Computed only once per unique project name const slug cachedSlugify(project.name) return ProjectCard key{project.id} slug{slug} / })} /div ) }要点拆解缓存生命周期Map 声明在模块顶层跨组件实例、跨渲染周期存活组件卸载后缓存仍在后续重新挂载可直接命中命中路径has()get()是 O(1) 查找命中后直接返回不再调用slugify写入路径未命中才执行真实计算并set()记录结果Map 键类型规则示例是Mapstring, string理论上可用任意可区分类型的键若键是对象需注意引用相等语义见下文适用边界。通用化封装成可复用的缓存函数在大型代码库中同一模式会反复出现。可以将缓存包裹抽象为一个小工具函数例如function memoizeTArgs extends unknown[], TResult(fn: (...args: TArgs) TResult): (...args: TArgs) TResult { const cache new Mapstring, TResult() return (...args: TArgs) { const key JSON.stringify(args) if (cache.has(key)) { return cache.get(key)! } const result fn(...args) cache.set(key, result) return result } } const cachedSlugify memoize(slugify)注意JSON.stringify作键要求参数可序列化且序列化结果唯一复杂对象入参时需要谨慎。单值函数的简化模式单个变量即可当函数只有一个当前值而不是一组输入-输出映射时规则建议用单个模块级变量代替 Map更轻量let isLoggedInCache: boolean | null null; function isLoggedIn(): boolean { if (isLoggedInCache ! null) { return isLoggedInCache; } isLoggedInCache document.cookie.includes(auth); return isLoggedInCache; } // Clear cache when auth changes function onAuthChange() { isLoggedInCache null; }这个模式适合全局唯一状态类函数缓存值只有一个用null作为未缓存哨兵值第一次调用时计算并写入之后直接返回。关键配套动作是提供失效入口——onAuthChange()将缓存重置为null保证登录态变化后重新读取。同样的思路也适用于其他同步昂贵的单值来源。在 ZCode 仓库中js-cache-storage.md 规则就给出了 cookie 缓存的变体用Recordstring, string | null缓存document.cookie解析结果避免每次调用都同步解析 cookie 字符串。为什么用 Map 而不是 Hook规则明确强调Use a Map (not a hook) so it works everywhere: utilities, event handlers, not just React components.这是本规则与 React 生态常见做法的关键区别React Hook如useMemo只能在组件/自定义 Hook 中调用且缓存随组件实例销毁而失效同一组件卸载重挂载后缓存即丢失模块级 Map 属于纯 JS 机制可以在工具函数、事件处理器、非组件模块中直接使用适用范围更广模块级缓存在组件实例间共享多个列表、多次渲染复用同一份结果。因此这条规则适用于一切非组件作用域的重复计算场景而不只是 React 渲染路径。它属于 JavaScript 性能优化而非 React 专属优化。缓存失效外部可变数据必须显式清理规则正文要求 Clear cache when auth changes这是模块级缓存最重要的工程纪律凡是底层数据可能被外部改变的场景都必须提供失效机制否则会读到陈旧值。结合 js-cache-storage.md 中的配套实践典型的失效触发源包括// 存储可能在外部变化另一个标签页、服务端设置的 cookie需要失效缓存 window.addEventListener(storage, (e) { if (e.key) storageCache.delete(e.key); }); document.addEventListener(visibilitychange, () { if (document.visibilityState visible) { storageCache.clear(); } });失效策略取舍可结合 LRU 缓存思路参见同目录 server-cache-lru.md失效触发点实现方式适用场景业务事件显式暴露clearCache()/ 置null登录态变化、配置更新跨标签页storage事件删除对应 keylocalStorage/sessionStorage页面重新可见visibilitychange后clear()cookie、服务端下发的数据容量上限限制 Map 大小 / LRU 淘汰无限增长的高基数输入如代码块仓库实证ZCode 中代码高亮缓存的真实实现规则并非纸上谈兵ZCode 仓库的 UI 层就有一个高度契合的落地案例packages/ui/src/lib/shikiHighlighter.ts 的 Shiki 代码高亮模块。它用多个模块级 Map缓存不同粒度的计算结果const highlighterCache new Map string, PromiseHighlighterGenericBundledLanguage, BundledTheme (); const tokensCache new Mapstring, TokenizedCode(); const subscribers new Mapstring, Set(result: TokenizedCode) void(); // 内存诊断计数器tokensCache 目前无淘汰是审计里 // renderer 最可疑的增长点先把条数落到日志里。 uiMemoryDiagnosticsRegistry.register(shiki, () ({ tokensCache: tokensCache.size, highlighters: highlighterCache.size, }));从中可以观察到规则的完整实践形态highlighterCache缓存createHighlighter()的 Promise按theme:language组合建键——避免同一主题/语言重复创建昂贵的 Shiki 高亮器实例tokensCache缓存TokenizedCode词法分析结果键由getCodeTokensCacheKey()构造theme:language:length:head:tail在 highlightCode 入口 命中后直接返回缓存结果并推迟到微任务通知订阅者避免同步 setState 触发 React 嵌套更新subscribers缓存每个 cacheKey 的回调订阅集合供异步高亮完成后的分发使用。更有价值的是该文件还展示了模块级缓存必须配套的容量治理注释明确承认tokensCache目前无淘汰、是 renderer 最可疑的内存增长点并借助uiMemoryDiagnosticsRegistry把两个缓存的大小实时登记到内存诊断日志中。这印证了规则的深层含义——缓存本质是用内存换时间基数无界时必须考虑淘汰与观测。而缓存命中时通过queueMicrotask异步回调的设计则体现了缓存不只是减少计算还要与渲染调度协同的工程细节。与相邻规则协同形成一套完整的缓存优化体系js-cache-function-results并非孤立规则它与同类别规则构成互补在实际重构中常组合使用规则文件主题与本规则的分工js-index-maps.md为重复查找构建索引 Map把 O(n) 的find循环变成 O(1) 的 Map 查找1M ops → 2K opsjs-cache-property-access.md循环内缓存属性访问把热路径中重复的属性链取值提升到循环外js-cache-storage.md缓存 Storage/Cookie 读取把同步昂贵的 I/O 读取缓存到内存并处理失效server-cache-react.md服务端React.cache()服务端按请求去重与本规则的客户端模块级缓存对应组合原则先识别热点哪个函数被重复调用、再选缓存容器Map / 单值变量、最后定失效策略。这与 js-set-map-lookups.md用 Set/Map 做 O(1) 查找一脉相承共同构成了减少重复工作的优化主线。适用边界与注意事项只缓存纯函数依赖外部可变状态时间、随机数、用户输入、DOM 实时值的函数缓存会返回陈旧结果警惕内存增长高基数字符串输入如代码高亮的每段代码会让 Map 无限膨胀需要容量上限或 LRU 淘汰参见 server-cache-lru.md 的思路迁移到客户端多实例语义模块级缓存是全局共享的如果不同组件希望拿到不同版本的结果需把区分维度纳入缓存键SSR/同构环境模块级可变状态在服务端渲染RSC/SSR场景可能跨请求泄漏应遵循同目录 server-no-shared-module-state.md 的约束仅在客户端模块或明确安全的场景使用可观测性参考 shikiHighlighter 的做法为缓存接入诊断/日志出现内存问题时能快速定位。小结js-cache-function-results规则给出的方案简洁而通用纯函数 模块级 Map 显式失效。它用最少的代码消除了渲染期最高频的冗余计算且不依赖 React 运行时可在组件、工具函数、事件处理器中统一生效。ZCode 仓库中 Shiki 高亮模块的多级 Map 缓存与内存诊断实践展示了这一模式在真实产品中的完整落地形态——既要缓存命中率也要关注缓存本身的规模与生命周期。在编写或重构 React 组件时若发现同一输入被反复计算优先考虑这条规则往往能以最小改动获得稳定可观的性能收益。赞分享人工智能大模型代码智能体AI Agent桌面应用后端前端CLI【免费下载链接】ZCodeZCode 是 AI 编程工作台提供桌面应用、浏览器界面和终端 Agent。本仓库包含客户端、后端服务、共享 UI以及 Agent CLI 与运行时源码。项目地址https://gitcode.com/zai-org/ZCode点击查看免费下载相关推荐React 重复函数调用缓存用模块级 Map 消除冗余计算Vercel React 性能实践React 重复函数调用缓存用模块级 Map 消除冗余计算Vercel React 性能实践 导读 本文围绕 Vercel Engineering 发布的音视频桌面应用后端OpenMontage 前端性能优化用模块级 Map 缓存重复函数调用消除渲染期冗余计算OpenMontage 前端性能优化用模块级 Map 缓存重复函数调用消除渲染期冗余计算 导读 在 React 组件渲染过程中对同一组输入反复调用相同的纯人工智能AI Agent音视频媒体生成工作流自动化缓存重复函数调用在 cal.com 前端用模块级 Map 消除渲染中的冗余计算缓存重复函数调用在 cal.com 前端用模块级 Map 消除渲染中的冗余计算 导读本文基于 cal.diycal.com 开源调度平台仓库内置的 ve后端前端企业应用上一篇3个简单技巧快速掌握League-Toolkit终极英雄联盟游戏体验提升方案下一篇终极指南如何在Windows上搭建专业级Syslog监控系统创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考