性能优化指南
建议
- 复用同一个 schema 对象,让默认验证器缓存命中。
- 通过
s.config({ cache })或new Validator({ cache })调整缓存策略。 - 对热点路径避免在循环中重复构造 DSL。
- 服务端应复用长生命周期的
Validator实例;每次请求都新建会重置验证引擎和实例缓存。 - 如果你已经自行管理底层验证实例,再考虑
SchemaUtils.validateBatch()这类批量路径。
当前 benchmark 基线
本节全部数值来自仓库跟踪的 test/benchmarks/performance-docs-snapshot.json,不再拼接不同 benchmark 报告。环境:Node.js v20.20.2、win32-x64、Zod 4.3.6;运行开始时间 2026-07-13T09:55:17.579Z。
该 full 场景矩阵包含 19 个计入胜负的可比场景和 1 个不计入胜负的异步抛错诊断场景(AV2_THROW);可比场景中 schema-dsl 胜 14/19,Zod 胜 5/19。接近持平的场景可能在不同运行中切换胜方,因此这个矩阵只作为本仓库的回归信号,不作为永久公开性能承诺。
矩阵的 JSON 报告会记录语义差异。这里比较的是双方最接近的受支持行为,不表示所有场景的内部实现语义完全相同。
这些数字适合作为当前项目的回归基线。Node.js、依赖、schema 复杂度或错误格式化行为变化后,应重新运行 benchmark。
推荐做法
请求级 DSL 与内存边界
调用 s() 本身不会保留无限增长的全局状态。生产环境真正需要避免的不是“每次请求调用 s() 必然泄漏”,而是在热点路径上生成无限多种不同的 schema 结构。
内置缓存对“相同 schema 结构被重复使用”的场景有效。它无法让无限多、从不重复的新 schema 变便宜:schema-dsl 自身的受控缓存有容量边界,但每次未命中仍要承担转换和 validator 编译成本。
服务端 Validator 生命周期
普通 API 请求中不要每次都创建新的 Validator:
如果实例没有被长期持有,这通常不是长期内存泄漏;问题在于它会丢弃实例级缓存,并让新的 validator / 缓存对象不断进入分配和 GC。推荐使用一个应用级 validator,或按不同配置 profile 维护少量 validator。
对确实不可复用、基数很高的一次性动态 schema,可以隔离这条路径并让 validator 短生命周期存在,但不要把请求内创建的 validator 或 schema 对象存入应用级集合。
什么时候需要更低层优化
- 你要长期复用同一个
Validator实例并观察命中率。 - 你需要显式控制缓存大小、TTL 或统计开关。
- 你已经维护底层验证实例,需要走
SchemaUtils.validateBatch()。
验证命令
回归门禁会对每个被跟踪的场景运行三次并取中位数。同一 Node.js、平台和 CPU 下,schema-dsl/Zod 比值必须不低于基线的 75%;绝对吞吐低于阈值时,只有同轮 Zod 也出现相同比例的主机负载下降才标记为 CALIBRATED,否则仍失败。环境不同时只使用同轮相对比值。这里的 Zod 是固定版本的校准负载,不构成产品性能宣传。
对应示例文件
示例入口: performance-guide.ts
说明: 展示复用同一个 schema / validator、读取缓存统计,以及 SchemaUtils.withPerformance() 包装后的耗时输出。