业务场景
事情的起因是我们 WMS 系统内有一个批量打印的功能,今天仓库反应第一次打印的速度大概是 2s,但是之后每次都越来越慢,到后面页面基本就直接卡死了.
从这个表现来看,这个问题基本可以定位成性能问题,而不是可以被 try...catch 到的异常.
想到的解决方案有两种:
一行行 review 这部分相关的代码,console+debugger 来逐步排查问题.
使用 Chrome 自带的性能分析工具来定位问题.
一直没找到什么实践机会来使用这部分功能来定位问题,这次有了真实的业务场景,果断希望能用第二种方案来准确定位到问题.
内存泄露?
从表现上来看,感觉像是每次批量打印的时候导致了一部分内存泄漏,然后内存占比越来越高导致浏览器卡死.
这时候就需要用 Chrome 的 Memory 功能来统计下内存占比.在 Memory 下选择 Take heap snapshop,分析完成之后可以看到当前页面的各种对象的内存占比.当前我关注的不用那么细,只需要关注到页面的总内存,我在每次批量打印完成后都重新统计了页面占的内存,可以发现:每次内存占用有轻微上升,但肯定不会导致页面卡死.至此,可以排除掉是内存泄漏导致的问题.
使用 Timeline 分析
排除到内存泄漏的问题后,我能想到的页面被卡住的原因是 JS 脚本的执行时间过长.因为浏览器的渲染是单线程的,如果当前浏览器在进行 JS 脚本计算,那么在这个过程中 UI 线程是没法同时进行渲染改变的,所以看起来就是页面卡顿了.
这时候就需要用 Chrome 的 Timeline 分析工具(新版本 Chrome 里改成 Performance)来查看每一个函数调用的时长,来定位出问题的具体函数.
点击 record 按钮之后,然后多次调用批量打印功能,结束录制.得到了如图的分析结果:
图中可以明显看出第一次打印到第三次打印耗时增加很多,其中黄色部分代表脚本执行时间,紫色部分代表渲染时间.增加的时间部分主要是脚本执行时间导致的,这时候需要定位具体是哪个函数导致的脚本执行时间增加.
这时候可以查看火焰图部分,横坐标代表了消耗时间,纵坐标是调用栈关系,上面的栈调用下面的栈.一直从上往下找到最内层的函数调用,发现了导致耗时增加的函数是 JsBarcode,一个生成条形码的函数.
了验证这个结论,在代码里先注释掉这个函数,重新执行 Timeline 分析.得到如图的分析结果:
以看到因为脚本执行导致的时间增加问题已经解决了,但是渲染的时间还是随着每一次的打印都会增加,这时候开始分析渲染的问题.查看渲染部分详情可以看到右上角的一个三角形,这个三角形代表这里存在异常,并且 Chrome 给出了相应的警告(Forced reflow):
就是说这里强制重绘了界面,但是至此还是没理解为什么会重新绘制页面,这里强大的 Chrome 直接给出了影响渲染的代码片段,scrollbar-width 这个文件是 element-ui 的一个工具函数.
这时候查看 element-ui 源码对这个文件的引用情况,一层层往上定位发现在当前页面使用到的 table 组件和 message-box 组件里都引用到了这个文件.table 组件会在列表数据刷新的时候调用到这个函数,而 message-box 会在弹出的时候调用到这个函数.
为了验证这个猜想,注释掉列表更新和弹框的代码,重新使用 Timeline 分析,发现刚才的三角形不见了,这时候页面被重新绘制的问题也找到了.
此,导致增加打印时长的两个问题 1. 脚本执行 2. 页面渲染 都已经被定位到了,但是导致问题的业务代码还没改呢!也就是为什么绘制条形码的函数和重绘页面的时间会越来越长呢?
解决问题
问题已经分析到这了,很轻易想到了这部分功能里唯一一句相关的 DOM 操作代码,在每次打印一张快递单的时候都会 appendChild 一段 DOM 到 body 上(为了绘制二维码以及转 canvas 导出图片),但是每次 appendChild 之后并没有去 remove 掉这段冗余的 DOM(逃.
回滚 debugger 的时候的修改代码,添加 removeChild 操作.重新执行 Timeline 分析,可以看到三次打印的耗时已经一致了.明天让 QA 小哥哥测试一下可以上线了~
总结
最终定位到错误比较低级,不过这次实践基本是从 Chrome 强大的性能分析工具定位到了问题,虽然如果采用方案 1 去 review code 来排查最终也能定位到问题.但是可以想象,当业务代码足够复杂,函数调用层级很深的时候,去 review code 来排查的效率就会远不如利用 Timeline 分析的效率高了.
今天听了云音乐的校园十佳,写了一篇博客,忽然想吟诗一首,苟利国家生死以(逃
参考资料
developers.google.com
全新 Chrome Devtool Performance 使用指南
原 文: 网易考拉前端
作 者:yeomanyang
来源: https://sdk.cn/news/8056