页面resize卡顿问题修复记录

519 阅读2分钟

问题起因

某现场反馈我们的数据大屏在全屏时效果不佳,有很明显的卡断感。于是便处理并记录一下相关问题。

排查过程

首先手动拉伸一下页面,模拟一下resize操作,看看页面的火焰图

image.png

额 好吧,现场反馈的很有道理。

看了看火焰图的调用栈,初步定位到是代码的自适应逻辑有问题。然后又发现了一个浏览器警告:

image.png

下面竟然全是强制回流

什么是强制回流

之前在李兵老师的课程里看过这方面的介绍,也称之为强制同步布局。这次在实践中遇到,不得不回去再梳理一下

如果一段正常的处理dom的代码

    let node = document.createElement("div")
    html.appendChild(node);

image.png

那么浏览器会将其分为执行script计算布局,渲染两个任务,但是如果在代码下再加入一行,变为

    let node = document.createElement("div")
    html.appendChild(node);
    console.log(node.offsetHeight);

则对应的火焰图会变为:

image.png

因为浏览器要在执行script的任务中输出node的宽度,所以必须将node先渲染出来,从而导致必须在同一个任务中完成渲染操作,这就是强制同步布局

回到项目代码

发现resizeAll下面包含一段一段这样的逻辑

    resizeA();
    resizeB();
    resizeC();
    resizeD();
    resizeE();

而每一个resize中都调用了document.documentElement.clientWidth,从而造成强制同步布局问题。

改成如下代码后

    this.currentClientWidth = document.documentElement.clientWidth;
    resizeA();
    resizeB();
    resizeC();
    resizeD();
    resizeE();

再次查看火焰图:

image.png

比之前好挺多了,但还是有卡顿帧,仔细查看发现resizeAll函数和swiper中的resize在同一个task中执行了。swiper中竟然还有监听resize的相关操作,swiper你好卑鄙。

image.png

最后给resizeAll加了一个30ms的防抖,得到火焰图如下:

image.png

已经没有卡顿帧了,该问题到此告一段落。