以 ~2000+ 的变体表示“ 最大调用堆栈大小超过”
□ 你用什么版本的Ajv?
8.17.1 联合国
□想解决什么问题?
当一个JSON Schema含有一个有大量变体(大约2 000+)的Of'时,ajv.compile ()'成功,但由此产生的验证函数在调用时会抛出RangeError:最大调用堆大小已超过'。 在更高的计数(~3,000+)中,编译()'本身崩溃了。
这不是一种精心构思的情景——我们维持一个浏览器A/B测试平台的图案,其中特征旗帜和实验参数被描述为`One Of'阵列,其中5 000-10 000+变体来自登记册。
□ 根源
Of'编码源(vocabularies/applicator/of.js')释放出`if/ else {if {.}-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 这就产生了两个问题:
在编码时:
如果.reserve ()'在Compile/codegen/index.js'中是递归性的——每个如果'节点称为this.else.reserve (opts)'。 有N变体的调用堆栈深度为O(N). 在~3000个变体时,这超过了V8的默认堆栈限制和"编译()"抛出.在验证过程中:即使编码基因成功(如N = 2 000),所生成的JavaScript函数本身包含有~2 000级的嵌入式 " if/else " 区块。 当 V8 执行此函数时, 它再次溢出调用堆栈 。
设置“ 代码 : { 优化: 假的 : 仅禁用“ 优化节点( ) ” (它有自身的重复问题) , 但无助于“ 放弃( ) ” 或生成的代码结构 。
QQ 相关代码路径
编译/codegen/index.js':else Node()' (行~616)将上个If.else'内的每一个新的Else'连在一起,形成O(N)的筑巢深度。If.render()' (行~199) 递归称this.else.render()'。vocabularys/applicate/Of.js':每个变体的schema.one.of'称为gen.if(.)'/.else(.)'。
□ 最小复制
{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你来干什么? // issue-repro.mjs- 运行: npm 安装 ajv- QQ 节点 issue-repro.mjs 从“ jev” 导入 Ajv ;
函数 makeSchema(n){ 返回{ 其中一个: 从({ 长度: n }), ( ,i) {{{ 类型: "对象", 需要: [“名称”], 属性 :{ 名称 : { const: `变量 ${i}}, {\fn华文楷体\fs16\1cHE0E0E0} ·)),
- ; {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢?
(单位:100,500,1000,2000,3000){ const ajv = 新 Ajv({严格:假,代码:{优化:假}}; cn) = makeSchema(n); const t0 = 性能. now(); 尝试{ const 验证 = ajv.compile(schema); const t1 = 性能. now(); ; 尝试{ cont results = 验证({名称:"变量 0"}); cont t2 = 性能. now(); 控制台.log () “ 1OF( ${n} ): 汇编 ${( t1 - t0) ; toFixed( 0)}ms, 校正 ${( t2 - t1)} toFixed( 0)}ms, 结果= ${结果} (三) {\fn华文楷体\fs16\1cHE0E0E0}抓住 控制台.log () `Of( ${n} ) : 编译 OK ${(t1 - t0) ; toFixed (0)}ms, 验证 () CASHED - RangeError' (三) {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢? {\fn华文楷体\fs16\1cHE0E0E0}抓住 cons ms = (性能. now () - t0; to Fixed (0); ; ). a. 控制台.log( 'One Of (${n}): 汇编 () ${ms} ms- RangeError 之后的 CASHED ; {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢? {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢?
* 预期产出
所有大小都应汇编和验证
. . . . . . .内容来源: ajv-validator/ajv