问题起因
某现场反馈我们的数据大屏在全屏时效果不佳,有很明显的卡断感。于是便处理并记录一下相关问题。
排查过程
首先手动拉伸一下页面,模拟一下resize操作,看看页面的火焰图
额 好吧,现场反馈的很有道理。
看了看火焰图的调用栈,初步定位到是代码的自适应逻辑有问题。然后又发现了一个浏览器警告:
下面竟然全是强制回流
什么是强制回流
之前在李兵老师的课程里看过这方面的介绍,也称之为强制同步布局。这次在实践中遇到,不得不回去再梳理一下
如果一段正常的处理dom的代码
let node = document.createElement("div")
html.appendChild(node);
那么浏览器会将其分为执行script和计算布局,渲染两个任务,但是如果在代码下再加入一行,变为
let node = document.createElement("div")
html.appendChild(node);
console.log(node.offsetHeight);
则对应的火焰图会变为:
因为浏览器要在执行script的任务中输出node的宽度,所以必须将node先渲染出来,从而导致必须在同一个任务中完成渲染操作,这就是强制同步布局
回到项目代码
发现resizeAll下面包含一段一段这样的逻辑
resizeA();
resizeB();
resizeC();
resizeD();
resizeE();
而每一个resize中都调用了document.documentElement.clientWidth,从而造成强制同步布局问题。
改成如下代码后
this.currentClientWidth = document.documentElement.clientWidth;
resizeA();
resizeB();
resizeC();
resizeD();
resizeE();
再次查看火焰图:
比之前好挺多了,但还是有卡顿帧,仔细查看发现resizeAll函数和swiper中的resize在同一个task中执行了。swiper中竟然还有监听resize的相关操作,swiper你好卑鄙。
最后给resizeAll加了一个30ms的防抖,得到火焰图如下:
已经没有卡顿帧了,该问题到此告一段落。