记录一个bug,逻辑错误,结果正确,异步代码调试及IE下的渲染机制

来源:互联网 发布:java性能监控系统 编辑:程序博客网 时间:2024/06/06 01:44

近来已经很难遇到让人打起精神来对付的bug了。

这是一个弹窗上的操作,这个项目使用了bootstrap中的modal插件。在IE9下面发现有参数没有提交过去。但是在chrome上提交的参数是正常的。

调试发现运行到正式提交的那个方法,有一个判断,if($(‘.input_part.sign_change:visible’).length>0),在IE9下,这个值是false,也就是找不到该元素。这个元素是弹窗上的一个元素,此时的情况是这个元素我明明还能看见它,但是代码却找不到它了。

难道是IE浏览器的bug?难道我眼睛看到的并不一定是真的?

于是更大范围的调试,发现在某一个方法中,执行了$.closeModal(),关闭了弹窗,这显然是一个逻辑错误,此时并不应当关闭弹窗,我们只要加入一些判断,让这个$.closeModal()在当前情况下不执行,IE下功能就正常了,代码的逻辑也正常了,到此,bug解决。但是我们遇到bug不仅仅是解决bug就够了,能从bug中有所收获当然更好。

分析原因:弹窗已关闭并删除,于是在dom树上这个弹窗已经找不到了,但是界面还没有重新绘制。所以我们眼睛看到的弹窗其实已经不存在,这是浏览器渲染机制的问题。
观察到弹窗消失的时间是发送ajax请求,让出线程的时候。

于是IE下的这个奇怪的问题似乎有了可靠的解释,那么问题到这里就结束了吗?不,并没有,因为更诡异的是这样的逻辑有问题的代码在chrome上居然按代码编写者所预期地进行了!

代码还原到错误逻辑,转战chrome。
执行$.closeModal(),弹窗正常消失(IE下不消失),$(‘.input_part.sign_change:visible’)元素依然能找到!!
这就是之前错误代码能正常运行的原因:界面重新绘制了,dom树没有更新?
然后发送ajax请求,让出线程。再运行$(‘.input_part.sign_change’),发现已经找不到元素,dom树已更新。

看起来似乎这个解释也很圆满。但是这跟我一贯的认知并不太符合,如果我们的代码操纵了dom树,但是dom树没有更新,那么我们后面的代码还有什么可以相信的?

于是将场景抽离,把弹窗相关组件抽出,情景模拟简化,发现chrome下的分析果然有问题。
测试发现这个closeModal()方法在弹窗加入了动画效果fade的时候是并不完全是一个同步的操作。所以在动画效果结束之后才会真正设置弹窗display:none并删除dom,在此之前只会把组件的opacity属性由1变成0,也就是肉眼不可见,其实元素还存在,并且jQuery的$(‘:visible’)依然可以找到它,所以我们后面的代码执行才没有问题。让组件display:none并删除dom的操作则是一个异步操作,在主线程让出循环之后它才会执行。

而在IE下。测试发现过程弹窗显示与关闭是同步操作。到bootstrap的modal插件源码调试了一下发现IE9中确实是同步操作。IE9中的情况我们上面分析是正常的。dom元素已删除,界面未有即时更新。$(‘:visible’)以及原生document.querySelector都无法找到元素了。

到此,一个逻辑错误的代码,在IE下不能正常运行和chrome下能“正常”运行的原因我们都找了出来。

注:之所以会删除dom。是我们额外添加了hidden.bs.modal事件。会在弹窗完全消失之后删除dom。

同步发表在:github

阅读全文
0 0
原创粉丝点击