美文网首页
重绘和重排及其性能优化

重绘和重排及其性能优化

作者: 我向你奔 | 来源:发表于2018-03-21 17:39 被阅读125次

    了解了浏览器渲染原理之后,我们知道了浏览器听过渲染树计算布局后,就开始绘制页面元素,但是渲染树并不是一成不变的,在我们的脚本当中它是可能改变的。

    什么是重排和重绘

    重排:若渲染树的一部分更新,且尺寸变化,就会发生重排,可以理解为渲染树需要重新计算;重排会从 <html> 这个 root frame 开始递归往下,依次计算所有的结点几何尺寸和位置。
    重绘:一个元素外观的改变所触发的浏览器行为,例如改变visibility、outline、背景色等属性。浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。重绘不会带来重新布局,并不一定伴随回流。

    重排何时会发生

    (1)增加或删除DOM节点;
    (2)display:none(重排并重绘);visibility:hidden(重绘);
    (3)移动页面中的元素;
    (4)改变元素尺寸(宽、高、内外边距、边框等);
    (5)用户改变窗口大小,滚动页面等;
    (6)页面初始渲染;
    (7) 改变元素内容(文本或图片等);

    浏览器的优化:渲染队列

    重排只要出现,就会重新对DOM树进行渲染,而大多数时候,这种全局性的渲染是没必要的,不管页面发生了重绘还是重排,次数多了,性能就差。

    比如我们想用js中修改一个div元素的样式,写下了以下代码

    div.style.left = '10px';
    div.style.top = '10px';
    div.style.width = '20px';
    div.style.height = '20px';
    

    我们修改了元素的left、top、width、height属性,满足我们发生重排的条件,理论上会发生4次重排,但是实际上只会发生1次重排。

    这是因为我们现代的浏览器都有渲染队列的机制,当我改变了元素的一个样式会导致浏览器发生重排或重绘时,它会进入一个渲染队列,然后浏览器继续往下看,如果下面还有样式修改,那么同样入队,直到下面没有样式修改,浏览器会按照渲染队列批量执行来优化重排过程,一并修改样式
    这样就把本该4次的重排优化为1次。

    但是我们现在想要修改样式后在控制台打印:

    div.style.left = '10px';
    console.log(div.offsetLeft);
    div.style.top = '10px';
    console.log(div.offsetTop);
    div.style.width = '20px';
    console.log(div.offsetWidth);
    div.style.height = '20px';
    console.log(div.offsetHeight);
    

    这样写的话就会发生4次重排,因为offsetLeft/Top/Width/Height非常叼
    它们会强制刷新队列要求样式修改任务立刻执行,毕竟浏览器不确定在接下来的代码中你是否还会修改同样的样式,为了保证获得正确的值,它不得不立刻执行渲染队列触发重排。

    以下属性或方法会刷新渲染队列:

        offsetTop、offsetLeft、offsetWidth、offsetHeight
        clientTop、clientLeft、clientWidth、clientHeight
        scrollTop、scrollLeft、scrollWidth、scrollHeight
        getComputedStyle()(IE中currentStyle)
    

    我们在修改样式过程中,要尽量避免使用上面的属性。

    如何减少重绘和重排以提升页面性能

    (1)不要一个个修改属性,应通过一个class来修改
    错误写法:

    div.style.width="50px";div.style.top="60px";
    

    正确写法:

    div.className+=" modify";
    

    (2)clone节点,在副本中修改,然后直接替换当前的节点;
    (3)若要频繁获取计算后的样式,请暂存起来;
    (4)前面说到,回流的危害在于重新对DOM树进行渲染,那么,脱离文档流之后,进行的任何操作,都不会造成回流了!如果有需要经常进行复杂操作的地方,使用position:absolute/fixed定位,使之脱离文档流后进行操作,或者使用display:none,操作完成后再进入到文档流之中。
    (5)批量添加DOM:多个DOM插入或修改,应组成一个长的字符串后一次性放入DOM。使用innerHTML永远比DOM操作快。(特别注意:innerHTML不会执行字符串中的嵌入脚本,因此不会产生XSS漏洞)。
    (6)以下这些属性,只要是改动了他们的值,就会造成回流,建议将他们合并到一起操作,可以减少回流的次数。这些属性包括:offsetTop、offsetLeft、 offsetWidth、offsetHeight;scrollTop、scrollLeft、scrollWidth、scrollHeight;clientTop、clientLeft、clientWidth、clientHeight;getComputedStyle() 、currentStyle()。

    相关文章

      网友评论

          本文标题:重绘和重排及其性能优化

          本文链接:https://www.haomeiwen.com/subject/iazgqftx.html