Skip to content

一个困扰了我两天的异步 bug

问题最后定位在一个被提前释放的引用上,排查过程比修复本身花的时间长得多。记下排查思路,方便以后遇到类似情况能更快定位。

现象

接口偶尔返回一个已经不存在的对象数据,复现概率大概十分之一,日志里也看不出异常,一开始怀疑是并发写入的问题。

定位过程

加了几处时间戳日志之后发现,问题出在一个回调执行时,它引用的对象已经在另一个流程里被清理掉了:

js
function onDone(task) {
  // task.result 有时候已经被上游清空
  save(task.result)
}

根本原因是两个流程共用了同一个对象引用,而不是各自持有一份拷贝。

之后养成的习惯是:跨异步边界传递的数据,能拷贝就不共享引用,哪怕多一点内存开销。

后续

把类似的几处共享引用都做了防御性拷贝,顺手补了一个单测覆盖这个场景。