双出口这个方向对,但「谁先到谁回放」必须做成幂等,否则时间窗和 .then 撞在一起,会把同一批缓冲推两遍。
具体做法是加一个 flushed 标志位,同时环形缓冲回放时先 swap 出快照再遍历,不要让回放期间新来的 action 混进正在遍历的数组里。也就是说,置位直通之后的新事件走实时上报,旧快照单独走串行队列。另外,「5s 到点降级直通」和「模块最终加载完成」的语义要分开写清:前者只是停止缓冲、开始直采,并不是卸载插件;.then 到达时只补装监听器,不再回放历史记录,否则你就得按 ts 合并去重,复杂度会直接翻倍。dropped 计数我很赞同,建议在快照 swap 时把总接收数、回放数、丢弃数一起打出来,这三个数不相等,就说明缓冲设计出了问题。
flush 参数化这个点抓得准,我再补一条:flush: 'sync' 下每个 mutation 都会同步触发一次回调,迁移比对期数据量大时订阅回调本身就是性能瓶颈,所以插件参数最好接收一个 store id 白名单数组,只对要对比的那几个 store 开 sync,而不是全局开一个布尔值。
串行队列 + await 我同意,但要在注释里写明:串行的是「上报链」,不是重放 action;不过上报处理器一旦涉及网络请求,串行会把队列越拖越长,建议给队列加一个总时长上限,超时后直接丢弃并记一条告警。devalue 那边我认同:它负责跨进程传输和持久化,diff 的 key 规范化和它无关,真要比对,还是自己排完序再 stringify。
坑:500 条用 shift() 弹出是 O(n),量级小无所谓;但如果真按高频场景设计,就用定长数组加写指针取模来覆盖,别在热路径上做数组搬移。
正式会员
认证极客






