三条都成立,但第一条的修法得再往下想一层——WeakSet 只对原始对象生效,不能在「包装后再打标」的顺序里用,否则永远命中不了。
关于非 Error 对象:正确做法是把打标和归一化分成两个阶段,打标是「尽力而为」的前置步骤,只对 typeof err === 'object' && err !== null 生效;然后无论打没打上标,都统一归一化成内部结构 { kind, message, stack } 再进 Map 合并。关键是两条路径产出同一种 report 结构,下游不关心它是对象还是字符串。如果反过来先包装成对象再 add 进 WeakSet,每次都是新引用,等于白打。
关于 Map 上限:200 条这个数没问题,但淘汰策略建议不要「丢最旧」。firstAt 最早的那条往往是持续爆发的老错误,淘汰它反而欠采样;按「最久未被命中(LRU)」或「count 最低」淘汰更合理。另外强制 flush 要防递归:flush 本身失败又入队会立刻再次超限,建议加 flushing 标志,期间新错误进 overflow 缓冲,超了就直接丢弃并记 dropped++,上报时带上这个计数用来校准丢失率——否则你会以为错误变少了。
关于构建 hash 归一化:完全同意,补一点——归一化规则别写死正则。/assets/\w+-[a-f0-9]{8}\.js/ 只适合 Vite 默认输出,换 webpack 或用了 [contenthash:6] 就失效。建议初始化时传入一个 chunk 名映射表或用 /(?:[.-])[a-f0-9]{6,10}(?=\.(?:js|css))/ 这种更宽的规则。node_modules 帧的问题:monorepo 里 link 的自家包也在 node_modules 下,一律剔除会丢关键帧,折中是只剔除非 workspace 路径。CDN 前缀同理,用初始化时注册的域名白名单做归并,比猜主域名可靠。
self-disable 那条:加个前置判断,navigator.onLine === false 时不计失败次数,否则用户断网一次就把监控关了。
坑:打标层和合并层确实不能共用一个 try,最好连函数都分开,打标函数整个包 try 且不返回值。
见习用户






