zoukankan      html  css  js  c++  java
  • DOM的重绘和回流及代码性能优化

    1.DOM的重绘和回流Repaint&Reflow


    1.1重绘:元素样式的改变(但宽高、大小、位置等不变)


    如outline、visibility、color、background-color等

    1.2回流:元素的大小或者位置发生了变化(当页面布局和几何信息发生变化的时候),触发了重新布局,导致渲染树重新设计布局和渲染。


    如添加或删除可见的DOM元素;元素的位置发生变化,元素的尺寸发生变化,内容发生变化(比如文本变化或者图片被另一个尺寸不一样的图片替换);页面一开始渲染的时候(这是无法避免);因为回流是根据视口的大小来计算元素的位置和大小的,所以浏览器的窗口尺寸变化也会引发回流。

    注意回流一定会触发重绘,重绘不一定会回流。

    2.前端性能优化:避免DOM的回流


    2.1放弃传统操作DOM,基于vue/react开始数据影响视图模式


    可通过vue或react等框架中的virtual dom/dom diff,避免对DOM的直接操作。

    2.2分离读写操作(现代的浏览器都有渲染队列的机制)


    style样式

    <style>
        #box {
             100px;
            height: 100px;
            background-color: red;
            border: 1px solid yellow;
        }
    </style>
    

    body代码

    <body>
        <div id="box"></div>
        <script>
            //(1)
            let box = document.getElementById('box');
            box.style.width = '200px'; //大小发生变化,引发一次回流
            box.style.height = '200px';
            box.style.margin = '10px';
            //因为浏览器存在渲染队列机制,如果引发回流的语句挨在一起写,只会引发一次回流
    
            //(2)
            box.style.height = '300px';
            console.log(box.clientWidth); //不引发回流
            box.style.margin = '20px';
            //中间插入非引发回流语句,打断了任务队列,所以总共回流2次
    
            //(3)
            box.style.height = '300px';
            box.style.margin = '30px';
            console.log(box.clientWidth); //只引发一次DOM回流
            /*分离读写:就是把能引发回流的"写语句"与不能引发回流的"读语句"分开写,以减少回流次数*/
        </script>
    </body>
    

    2.3样式集中改变


    style样式

    <style>
        #box {
             100px;
            height: 100px;
            background-color: red;
            border: 1px solid yellow;
        }
        
        .a {
             200px;
        }
    </style>
    

    body代码

    <body>
        <div id="box"></div>
        <script>
            let box = document.getElementById('box');
            /*批量处理:把元素的多个样式统一修改减少DOM的回流*/
            //(1)直接添加多种样式
            // box.style.cssText = '200pxl;height:200px;';
            //(2)通过添加类名添加多种样式
            box.className = 'a';
        </script>
    </body>
    

    2.4缓存布局信息


    body代码

    <body>
        <script>
            let box = document.getElementById('box');
            //缓存处理(实质上属于分离读写)
            //(1)
            box.style.width = box.clientWidth + 10 + 'px';
            box.style.height = box.clientHeight + 10 + 'px';
            //由于box.clientWidth获取操作,终端了任务队列,上面语句触发两次DOM回流
    
            //(2)
            let a = box.clientWidth;
            let b = box.clientHeight;
            box.style.width = a + 10 + 'px';
            box.style.height = b + 10 + 'px';
            //先使用一个变量存储获取的数据,再进行写操作,就不会中断任务队列,只触发一次DOM回流。
        </script>
    </body>
    

    2.5元素批量修改


    body代码

    <body>
        <ul id="box">
    
        </ul>
        <script>
            //批量处理:在ul中动态创建5个li
            var box = document.querySelector('#box');
    
            //(1)
            for (let i = 0; i < 5; i++) {
                let newLi = document.createElement('li');
                newLi.innerHTML = i;
                box.appendChild(newLi);
            }
            //这种写法循环几次便会引发几次回流不可取
    
            //(2) 文档碎片
            let frg = document.createDocumentFragment(); //创建一个文档碎片的临时容器
            for (let i = 0; i < 5; i++) {
                let newLi = document.createElement('li');
                newLi.innerHTML = i;
                //创建的li先储存在文档碎片中
                frg.appendChild(newLi);
            }
            box.appendChild(frg);
            frg = null; //对于不用的容器,要进行销毁释放
            //相当于把文档碎片frg中的对象一次性添加到box中只引发一次文档回流。可取
    
            //(3)模板字符串拼接 (最优)
            let str = ``;
            for (let i = 0; i < 5; i++) {
                str += `<li>${i}</li>`;
            }
            box.innerHTML = str; //只引发一次回流
            //运用ES6的模板字符串,添加标签十分方便,并且能够有效减少文档回流,为最优方法。
        </script>
    </body>
    

    2.6动画效果应该使用position属性absolute或者fixed(脱离文档流)


    如果使用margin等属性对元素进行定位,会对其他元素的位置造成影响并导致回流。而使用position属性进行定位的元素能够脱离文档流,在一个新的平面上操作,虽然也会引起回流,但是不会影响其他元素,性能更好。

    2.7CSS3硬件加速(GPU加速)


    比起考虑如何减少回流、重绘,我们更期望的是,根本不需要回流和重绘;transform、opacity、filters...这些属性会触发硬件加速,不会引发回流和重绘。
    通常用的比较多的是transform(能用transform改变的样式绝对不用普通样式)。比如用translate属性来移动元素不会引起回流。
    缺点:用的多会导致占用大量内存,性能消耗严重。

    2.8牺牲平滑度换取速度


    简单地说就是动画总移动100px的情况下,每一秒钟移动1px,平滑度高,但是会引发100次回流;每一秒钟移动10px,平滑度相对较差,但是只会引起10次回流。当电脑比较快时可取前者,电脑较慢应取后者。

    2.9避免使用table布局


    由于table布局要一层一层的嵌套,添加完底层样式,才开始往外一层一层添加样式,不仅不好写样式,而且不利于DOM的性能优化。

  • 相关阅读:
    春招已近,这份GitHub万星的ML算法面试大全请收下
    [资源推荐] 必须收藏的两个查找论文和代码实现的网站!
    windows下安装pycocotools,亲测有效!
    GAN原理
    2018-07-02
    虚函数和纯虚函数
    友元
    string字符串
    实参和形参
    C/C++学习笔记汇总
  • 原文地址:https://www.cnblogs.com/AhuntSun-blog/p/11997031.html
Copyright © 2011-2022 走看看