事情的原由是咱们WMS系统内有一个批量打印的功能,今天仓库反应第一次打印的速度大概是2s,可是以后每次都愈来愈慢,到后面页面基本就直接卡死了。前端
从这个表现来看,这个问题基本能够定位成性能问题,而不是能够被try...catch到的异常。web
想到的解决方案有两种:chrome
一直没找到什么实践机会来使用这部分功能来定位问题,此次有了真实的业务场景,果断但愿能用第二种方案来准肯定位到问题。element-ui
从表现上来看,感受像是每次批量打印的时候致使了一部份内存泄漏,而后内存占比愈来愈高致使浏览器卡死。canvas
这时候就须要用Chrome的Memory功能来统计下内存占比。在Memory下选择Take heap snapshop,分析完成以后能够看到当前页面的各类对象的内存占比。当前我关注的不用那么细,只须要关注到页面的总内存,我在每次批量打印完成后都从新统计了页面占的内存,能够发现:每次内存占用有轻微上升,但确定不会致使页面卡死。至此,能够排除掉是内存泄漏致使的问题。浏览器
排除到内存泄漏的问题后,我能想到的页面被卡住的缘由是JS脚本的执行时间过长。由于浏览器的渲染是单线程的,若是当前浏览器在进行JS脚本计算,那么在这个过程当中UI线程是无法同时进行渲染改变的,因此看起来就是页面卡顿了。微信
这时候就须要用Chrome的Timeline分析工具(新版本Chrome里改为Performance)来查看每个函数调用的时长,来定位出问题的具体函数。markdown
点击record按钮以后,而后屡次调用批量打印功能,结束录制。获得了如图的分析结果:app
从图中能够明显看出第一次打印到第三次打印耗时增长不少,其中黄色部分表明脚本执行时间,紫色部分表明渲染时间。增长的时间部分主要是脚本执行时间致使的,这时候须要定位具体是哪一个函数致使的脚本执行时间增长。chrome-devtools
这时候能够查看火焰图部分,横坐标表明了消耗时间,纵坐标是调用栈关系,上面的栈调用下面的栈。一直从上往下找到最内层的函数调用,发现了致使耗时增长的函数是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分析的效率高了。
今天听了云音乐的校园十佳,写了一篇博客,突然想吟诗一首,苟利国家生死以(逃
author by yeomanyang