性能优化编年史¶
重要性:⭐⭐⭐⭐(性能演进——30+ profileCheckpoint + 启动优化 + 缓存层 + 预取策略) 范围:
src/utils/startupProfiler.js+ 所有 perf 优化点 方法:grep 性能相关代码 + 推断优化时间线
1. 启动 Profiler 体系¶
1.1 startupProfiler.js¶
profileCheckpoint('main_tsx_entry')
profileCheckpoint('main_function_start')
profileCheckpoint('main_warning_handler_initialized')
profileCheckpoint('main_client_type_determined')
profileCheckpoint('main_before_run')
profileCheckpoint('main_after_run')
profileReport() // 末尾输出
30+ profileCheckpoint 散布全文。
2 个核心 API:
- profileCheckpoint(name) —— 标记时间点
- profileReport() —— 输出总报告
1.2 数据流¶
启动 → checkpoint 1 → checkpoint 2 → ... → checkpoint N
↓
内存中累积
↓
profileReport()
↓
Statsig 上报 (sampled) + 控制台输出
2. 启动优化(4 大类)¶
2.1 顶部并行预取(main.tsx 行 1-20)¶
profileCheckpoint('main_tsx_entry')
import { startMdmRawRead } from './utils/settings/mdm/rawRead.js';
startMdmRawRead(); // 立即触发,与 import 并行
import { startKeychainPrefetch } from './utils/secureStorage/keychainPrefetch.js';
startKeychainPrefetch(); // 立即触发,与 import 并行
3 个并行预取:
- profileCheckpoint('main_tsx_entry') —— 埋点
- startMdmRawRead() —— MDM 读取(plutil/reg query)
- startKeychainPrefetch() —— macOS keychain 读取
节省:每次启动 ~200ms(macOS)。
2.2 Print 模式 fast-path(main.tsx 行 3880)¶
if (isPrintMode && !isCcUrl) {
profileCheckpoint('run_before_parse');
await program.parseAsync(process.argv);
return program; // 早返回,不注册 20+ subcommand
}
节省:~50-100ms(不注册 20+ subcommand)。
2.3 feature-gated 懒加载¶
const coordinatorModeModule = feature('COORDINATOR_MODE') ? require(...) : null;
const assistantModule = feature('KAIROS') ? require(...) : null;
const proactiveModule = feature('PROACTIVE') || feature('KAIROS') ? require(...) : null;
节省:商业版完全不打包这些模块。
2.4 首屏后预取¶
export function startDeferredPrefetches(): void {
if (isEnvTruthy(process.env.CLAUDE_CODE_EXIT_AFTER_FIRST_RENDER) || isBareMode()) {
return;
}
// 12 个 fire-and-forget
void initUser();
void getUserContext();
void getRelevantTips();
// ...
}
12 个 fire-and-forget —— 首屏后并行。
3. 缓存层(5 类)¶
3.1 memoize(永不失效)¶
插件加载 —— session 内只跑一次。
3.2 memoizeWithLRU(LRU 淘汰)¶
export const connectToServer = memoize(...); // MCP server
export const fetchToolsForClient = memoizeWithLRU(..., 20); // MCP tools (size 20)
MCP 缓存 —— 20 个 client LRU。
3.3 memoizeWithTTLAsync(时间过期)¶
export const refreshAndGetAwsCredentials = memoizeWithTTLAsync(...); // 1h
export const refreshGcpCredentialsIfNeeded = memoizeWithTTLAsync(...); // 1h
export const getApiKeyFromConfigOrMacOSKeychain = memoize(...);
3 个 TTL 缓存 —— AWS/GCP 1h,keychain 5min。
3.4 15 min Auth 缓存¶
MCP OAuth —— 15min 避免频繁重 OAuth。
3.5 5 min Helper 缓存¶
API key helper —— 5min 避免频繁调 shell。
4. 运行时优化¶
4.1 Hooks-first 架构¶
业务在 hooks —— 组件只编排。
好处: - 业务可独立测试 - 组件轻量 - 易复用
性能影响: - 组件 render 更快(业务在 hooks) - 业务不重复执行
4.2 useMemo 包裹重计算¶
const localTools = useMemo(() => getTools(toolPermissionContext),
[toolPermissionContext, proactiveActive, isBriefOnly]);
getTools 重计算 —— 只 dep 变才重算。
4.3 useCallback 包裹事件¶
50+ useCallback —— 防止子组件无谓重渲染。
4.4 useDeferredValue 打字不卡¶
低优先级渲染 —— 打字不卡。
4.5 useSyncExternalStore 外部 store¶
不会用 useState 不一致 —— 性能+正确性双赢。
4.6 精确 selector¶
不会全量订阅 —— 只在 verbose 变时重渲染。
4.7 React.memo¶
大组件 memo —— 防止父组件重渲染拖动。
4.8 Env-var 提到 mount-time¶
PageUp 滚屏 —— env check 只跑一次。
5. 内存优化¶
5.1 Yoga 4-slot cache¶
4-slot LRU —— 平衡内存和命中率。
5.2 MCP LRU 20¶
20 个 client —— 限制内存。
5.3 Snippet / Compact¶
对话过长 —— 压缩/截断。
5.4 Lite Session Info¶
不存完整 log —— 减少内存。
5.5 File History Delta¶
只存变化 —— 不存完整快照。
6. I/O 优化¶
6.1 1s getAttachments 总超时¶
1s abort —— 每次 LLM 调用前的"上下文拼装"不卡。
6.2 50ms bash parse 超时¶
50ms —— bash 解析不挂起。
6.3 50K node 预算¶
防 OOM —— 深层嵌套不爆内存。
6.4 Batch MCP 连接¶
分批 —— 避免 100 个 server 同时连。
6.5 settings 早期加载¶
早期加载 —— 后续 fast-path。
7. 字符串 / 解析优化¶
7.1 UTF-8 字节偏移¶
bashParser 用 byte offset —— UTF-8 安全。
7.2 黄金语料库¶
正确性 —— 大规模验证。
7.3 内容哈希(settings)¶
避免 prompt cache 失效 —— 12x token 节省。
7.4 sessionStorage 增量¶
只存变化 —— 不重存全部。
7.5 parallel + Promise.all¶
~30+ 处 并行处理。
8. 性能数字(推测)¶
8.1 启动时间¶
| 阶段 | 耗时 |
|---|---|
| Bun 启动 | ~50-100ms |
| 模块求值 | ~100-200ms |
| PreAction init | ~100-300ms |
| 第一个 render | ~50-100ms |
| 总冷启动 | ~300-700ms |
8.2 首 token 时间(TTFT)¶
| 模式 | 耗时 |
|---|---|
| 首次 prompt | ~500ms-1s(collect attachments + API) |
| 后续 | ~200-500ms(cache 命中) |
8.3 内存占用¶
| 状态 | 占用 |
|---|---|
| 刚启动 | ~50-100MB |
| 大 session | ~200-500MB |
| 含 plugin | +20-50MB/plugin |
9. 性能监控¶
9.1 getYogaCounters¶
Yoga 性能 metrics —— 暴露给上层。
9.2 useFpsMetrics¶
UI FPS 监控 —— 卡顿检测。
9.3 useFrustrationDetection¶
用户行为 —— 推断卡顿。
9.4 Event Loop Stall Detector¶
// ANT-ONLY
if ("external" === 'ant') {
void import('./utils/eventLoopStallDetector.js').then(m => m.startEventLoopStallDetector());
}
主线程阻塞检测 —— 500ms 报警。
9.5 Statsig 上报¶
远程监控 —— 采样上报。
10. 关键性能决策¶
10.1 纯 TS vs WASM¶
bashParser 选纯 TS: - 启动快(无 WASM 加载) - 50ms 解析足够 - 跨平台
10.2 Yoga 纯 TS 移植¶
无 N-API: - 启动快 - 跨平台无坑
10.3 hooks-first 而非 class¶
React hooks: - 业务可测 - 组件轻 - 易复用
10.4 speculative LLM¶
投机 LLM 调用: - 用户感觉瞬时 - 规则决定时消费或放弃
11. 性能 vs 功能权衡¶
11.1 缓存层多¶
功能:6 类缓存 代价:内存占用 + stale data 风险 决策:用 LRU / TTL 缓解
11.2 30+ profileCheckpoint¶
功能:可观测性 代价:微小性能损失 决策:值得(debug 价值高)
11.3 预取策略¶
功能:首屏后 12 个 fire-and-forget 代价:CPU 抢占 决策:可关闭(CLAUDE_CODE_EXIT_AFTER_FIRST_RENDER)
11.4 snipCompact¶
功能:长对话压缩 代价:信息损失 决策:保留关键信息
12. 改进方向(潜在)¶
12.1 进一步懒加载¶
hooks 还能更细粒度懒加载。
12.2 减少 main.tsx 体积¶
4683 行仍然很大。
12.3 优化 tool pool¶
103 个工具全加载 —— 可以按需。
12.4 减少 utils 数量¶
198 个目录 —— 合并相似。
12.5 引入 web worker¶
UI 线程卸载。
13. 关键洞察¶
13.1 性能是"演进结果"¶
不是"重写"——是逐步优化。
13.2 30+ checkpoint 是"可观测性"¶
埋点 = 优化前提。
13.3 缓存层 6 类¶
多层缓存 —— 平衡内存/性能。
13.4 投机 LLM 是"UX 黑魔法"¶
用户感觉瞬时 —— 实际异步。
13.5 启动优化 4 大类¶
顶部预取 / print fast-path / feature gate / 预取。
13.6 纯 TS 优先¶
启动 > 极致的解析速度。
13.7 env-var 提到 mount-time¶
PageUp 优化 —— 微小但真实。
13.8 React 性能 8 大手段¶
memo / callback / deferred / selector / sync / AppState / memo / useMemo。
13.9 性能权衡的"度"¶
不是"越多越好"——是"该用就用"。
14. 阅读建议¶
- 看 startupProfiler.js —— checkpoint 实现
- 看 main.tsx 顶部 20 行 —— 并行预取
- grep
memoize/memoizeWith—— 缓存层 - 看 React.memo / useCallback —— 组件层
- 看
useDeferredValue—— 打字不卡
15. 与其他分析的关系¶
| 文件 | 关系 |
|---|---|
architecture-history.md |
演进历史 |
module-dependencies.md |
模块依赖 |
extensibility.md |
扩展点 vs 性能 |