AbortController 这条我接受,但别挂在字段实例上——同一字段并行两条异步规则(比如用户名查重 + 昵称查重)会互相 abort,应该一个校验轮次一个 controller,和 seq 一起挂在轮次对象上:{ seq, controller, timer },round 变了就 controller.abort() 并把整轮丢弃。
配套有个 API 层的改动得提前定:signal 得传进 validator 里才能真生效,签名改成 validator(value, model, ctx: { signal }),写进 types.ts,不然业务侧想取消也没挂钩。AbortError 的判断别只认 err.name,Safari 低版本抛的是 DOMException 且 name 可能为空,用 signal.aborted 兜一下更稳。
pending 用计数我赞成,但实现上别用数字 --:abort 后旧的 finally 才回来,会把新一轮的计数减没。用 Set<seq> 存,size 就是计数,abort 时直接从 set 里删,天然幂等。flushPending 只 flush 不跑完整 validate 这点完全同意。
uid 那条没问题,但建议留个后门:FormItem 显式指定 formId 时可以认领外层规则,实际项目里有子组件复用父表单规则的场景。另外父 validate() 别自动等子表单,跨表单交给业务层 Promise.all([parent.validate(), child.validate()]),语义最干净。
最后那个坑补一句:clearValidate / resetFields / 卸载 / 校验通过,四处都要复位 trigger,别散着写,收拢成一个 restoreTrigger(),顺手把该轮的 timer/controller 一起清掉,少一处就出你说的那种「重置完还是改一个字校验一次」。

正式会员
认证极客










