0
0
0

那个让我调了四个小时的Bug,原因竟然是...

文章摘要
|

上周五,我差点因为一个Bug提桶跑路。

事情是这样的。我们负责的一个后台管理系统,用户反馈说某个列表页偶尔会白屏,不是必现,大概十次能复现两三次。这还不是最糟心的——生产环境才出现,本地和测试环境都是好的

我一开始以为是环境变量的问题,把dev、test、prod的配置翻来覆去对了一遍,没问题。又以为是打包的问题,webpack配置、代码压缩、sourcemap、tree shaking全部排查了一遍,还是没头绪。

然后我开始怀疑是数据问题。是不是某个接口返回了空数据,前端解构赋值的时候崩了?加了无数个可选链和默认值,问题依旧。

接着怀疑是浏览器兼容性,试了Chrome、Edge、Firefox,都能复现。甚至怀疑是某个第三方SDK搞的鬼,一个一个注释掉引入的库,还是没用。

整整四个小时,我看着屏幕,感觉它也在嘲笑我。

同事路过说:"要不你换个思路,看看Network面板?"

我深吸一口气,打开Network,刷新页面,一个一个请求看。突然注意到,接口响应里有一个字段的值是null,而其他地方这个字段都是数组。继续追下去发现,当这个字段为null时,页面某个组件里用了[].concat()的处理逻辑,看似没问题。但再往下走,这个值被传到了Array.prototype.sort()方法里——null没有sort方法,直接报错,但错误被某个全局的try-catch吞掉了,所以控制台什么都没显示

问题的根源是什么?后端某个特定条件下返回了null而非空数组,前端没有做防御性判断。为什么本地不报?因为本地mock数据写死了空数组。

花了四个小时,最终改动就一行代码:

javascript

const list = (response.data.list || []).sort((a, b) => a.order - b.order);

四个小时,一行代码。

这就是程序员的日常。你永远不知道一个看似简单的Bug背后藏着什么妖魔鬼怪。最折磨人的不是Bug本身有多难,而是你满世界找答案,结果答案就在眼皮底下,傻到不好意思跟人讲。

但我后来想明白了几点,写出来共勉:

  1. 永远不要假设数据是干净的——后端说"放心肯定不会为null",听听就好,该做的防御一个不能少

  2. 错误日志一定要打印完整——吞掉异常是灾难级的做法

  3. 先从网络请求看起——再花哨的问题,90%出在数据层面

  4. 调Bug的时候站起来走走——有时候换个姿势,思路就打开了

这条微博送给所有还在跟Bug斗智斗勇的兄弟姐妹们。你不是一个人在战斗。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或者给予支持!

评论

欢迎来到我的博客!