性能与 bundle 边界
诚实理解 Coaction benchmark,并让本地应用使用无 transport 的入口。
只有当场景、runtime、状态 shape 与包版本都可见时,性能结论才有意义。Coaction 将 benchmark script 保存在仓库中,便于重新生成结果,而不是把数字当成永久事实。
选择 local 入口
Vanilla 本地 store 应写为:
import { create } from 'coaction';该静态边界排除共享 protocol、epoch、重连与 transport module。共享运行时使用 coaction/shared,React 中使用 @coaction/react/shared;默认 @coaction/react 入口也只包含 local 运行时。
仓库的 bundle budget 测量发布入口与 tree-shaken consumer fixture。它们是回归门禁,不代表应用 bundle 必然等于预算数字;最终结果还取决于应用 bundler 保留的外部依赖。
运行维护的检查
pnpm build
pnpm package:size
pnpm benchmark
pnpm benchmark:zustand-positioning
pnpm benchmark:checkpackage:size检查发布入口预算与 core entry 隔离;benchmark对比大型 update path,包括 Coaction draft 与 Zustand + Immer;benchmark:zustand-positioning分离 stable derived read 与 update-then-read;benchmark:check以 CI 浮动余量执行回归下限。benchmark:derived在独立进程中使用构建后的入口,覆盖稀疏路径、相关/无关写入、全量扫描、缓存读取,以及尚未读取/已销毁的 owner。它已加入benchmark:check;全量 deep scan 的结果用于展示追踪成本,原生 getter 提供 coarse scan 基线。
不能仅为让失败结果变绿而降低阈值。阈值变化必须有经过 review 的 runtime semantic 或 benchmark methodology 理由。
理解派生状态 tradeoff
缓存 accessor 让稳定重复读取极快。更新后,Coaction 仍需维护 readonly public-state 边界,并更新 computed traversal 使用的 snapshot。因此“更新后读取派生值”与稳定缓存读取是不同路径。
除非集成明确需要 journal,否则不必设置 enablePatches。Commit hooks、共享 transport 和部分追踪路径会自动请求 patches。符合条件的小型依赖集合可以直接比较写入前后的已观察值,避免生成 patches;缓存 getter 快照、patch middleware 和较大的依赖集合仍保留 patch 路径。普通 subscribe() listener 自身不会请求 patches。
不要把其中一个 case 发布为普适的“快于 Zustand”结论。Zustand 可以通过存储派生值实现常量读取,但应用 action 必须负责一致性。Coaction 的价值是运行时维护的缓存派生,而非赢下每个 mutation microbenchmark。
渲染性能
原生 immutable store 上的 useStore(selector) 与 observer() 都使用可回收的深层路径追踪。读取 state.user.name 的 reader 可以在仅更新 age 的 recipe 后继续使用缓存。Selector 仍以 Object.is 比较结果;observer() 直接收集 render 中的读取,不需要额外 selector。请分别测量 selector 执行次数与组件 render 次数。
原生 getter 与 get(deps, fn) 仍以 store/slice 字段为边界。读取 this.user.name 的 getter 可能因 user.age 变化而重算,即使结果相同、消费者没有额外工作。需要更细依赖的派生读取可使用 derive(..., { deep: true }) 或 derivePath。
父对象 replacement、数组结构变化和 graph snapshot patches 可能扩大失效范围;外部 adapter 遵守各自的更新和快照 contract。具体边界见 computed 追踪粒度。
实用 checklist
- Vanilla 本地状态导入
coaction; - 非必要时不设置
enablePatches,同时考虑会自动请求 patches 的消费者; - 缓存 getter 用于重复派生读取,不承载副作用;
- 在确实减少 selector 组合时使用
observer(); - profile production build 与代表性状态;
- 把 benchmark floor 当作回归检测,并在目标机器重跑可发布数字。