zoukankan      html  css  js  c++  java
  • 转 小辉_Ray DOM性能小记

     在使用DOM操作时,同样的效果用不同的方式来实现,性能方面也会有很大的差异。尤其在移动式设备上,资源本来就很有限,一旦DOM写不好的话操作就会非常卡顿。这个周末,就写个DOM性能小记吧。错漏之处,望多指教。

      1、浅说reflow

      首先讲讲最近我才了解到的一个比较深入且模糊的东西——reflow

      从字面上理解的话,reflow有回流、重排的意思。它是指在DOM内容更新或增删时发生的一个响应过程,可以理解为页面内容改变了,然后发生重新排版这样的一个行为。我们可以将执行DOM操作细分为以下三个过程:读取HTML内容——>页面reflow——>展示更新内容。

      由于reflow是一个重整布局和样式的过程,相当消耗性能。所以我们优化DOM性能实际上就是避免执行更多DOM操作,即减少reflow过程

      2、减少reflow常用方法

      【1】采用临时变量存储,一次性操作DOM

        以我笔记本为例,分别测试了以下两段代码:

    复制代码
     1 //代码1
     2 window.onload = function(){
     3     var oUl = document.getElementById('ul1');
     4     for (var i = 0; i < 10000; i++) {
     5         oUl.innerHTML +=i;
     6     }
     7 }
     8 //代码2
     9 window.onload = function(){
    10     var oUl = document.getElementById('ul1');
    11     var str = '';
    12     for (var i = 0; i < 10000; i++) {
    13         str +=i;
    14     }
    15     oUl.innerHTML = str;
    16 }
    复制代码

      在chrome浏览器下用时取样如下,前五次为两段代码分别运行,后五次为放一起先后执行时间:

    t/ms 1 2 3 4 5 6 7 8 9 10
    代码1 9067.696 8900.826 9114.520 8987.592 9220.753 9344.496 8783.459 8797.731 9337.738 8835.503
    代码2 4.100 1.883 2.177 2.262 2.416 5.464 2.053 1.891 2.053 1.975

                                                                

      从上面数据明显看得出,同样执行10000次拼接,代码二远快于代码一。

      不难得出结论:减少DOM访问,改用外部变量临时存储内容,最后再一步执行DOM操作的效率远高于分次执行DOM操作。

      代码二的速度约是代码一的4000倍,可粗略计算出,innerHTML每查找并赋值一次,用时就接近1ms。

      【2】采用class修改多个样式,一次性更改属性

        分别测试以下代码:

    复制代码
     1 //代码三    
     2 window.onload = function(){
     3     var oUl = document.getElementById('ul1');
     4     for (var i = 0; i < 20000; i++) {
     5         if(i%2==0){
     6             oUl.style.fontSize = "18px";
     7             oUl.style.lineHeight = "30px";
     8             oUl.style.padding = "20px";
     9             oUl.style.width = "100px";
    10             oUl.style.height = "100px";
    11         }else{
    12             oUl.style.fontSize = "16px";
    13             oUl.style.lineHeight = "40px";
    14             oUl.style.padding = "30px";
    15             oUl.style.width = "200px";
    16             oUl.style.height = "200px";
    17         }
    18     }
    19 }
    20 
    21 //代码四
    22 window.onload = function(){
    23     var oUl = document.getElementById('ul1');
    24     for (var i = 0; i < 20000; i++) {
    25         if(i%2==0){
    26             oUl.className = "class1";
    27         }else{
    28             oUl.className = "class2";
    29         }
    30     }
    31 }
    复制代码

      同样在chrome浏览器下测试执行用时如下,前五次为两段代码分开运行,后五次为两段代码放一起运行(排除电脑不同时间点运行的差异):

    t/ms 1 2 3 4 5 6 7 8 9 10
    代码3 346.540 471.160 322.437 327.363 335.818 283.553 346.819 318.261 313.144 333.789
    代码4 38.666 20.042 19.550 26.465 27.294 38.429 33.793 37.031 34.928 36.221

                                            

       从上面的数据可以看出,通过设置class改变多个样式的方法比分次改变样式明显快得多。

      在不考虑js代码赋值运算增多带来了误差的情况下(实际上很小),代码4的方法平均耗时也比代码3的方法快10多倍。因为在代码3中,我每改变一个样式都会产生一次reflow,即reflow了5次。而在代码四中使用className却只reflow了一次,但一次reflow改变了多个样式

      这里需要注意的是,不是所有样式的改变都会产生reflow的。只有会影响布局的样式才会,例如width,height,display,line-height,margin,padding,font,background等等。诸如color,opacity,visibility等则不会,因为它们只会产生repaint。你可以想象得到,改变颜色、透明度等值对页面的结构是不会产生任何影响的。这里我就不展开讲了。

     【3】采用变量存储节点属性值,减少获取次数

       测试代码:

    复制代码
     1 //代码5
     2 for (var i = 0; i < 10000; i++) {
     3         if(i%2==0){
     4             document.getElementById('ul1').style.left = document.getElementById('ul1').offsetHeight + 10 + "px";
     5         }else{
     6             document.getElementById('ul1').style.left = document.getElementById('ul1').offsetHeight - 10 + "px";
     7         }    
     8     }
     9 
    10 //代码6
    11 var u1 = document.getElementById('ul1');
    12 var uW = u1.offsetHeight;
    13     for (var i = 0; i < 10000; i++) {
    14         if(i%2==0){
    15             u1.style.left = uW + 10 + "px";
    16         }else{
    17             u1.style.left = uW - 10 + "px";
    18         }    
    19 }
    复制代码

       分别执行以上代码10000次的10个时间样本对比:  

    t/ms 1 2 3 4 5 6 7 8 9 10
    代码5 1256.209 1175.189 1384.690 1241.207 1223.094 1371.524 1186.556 1176.889 1269.450 1215.922
    代码6 20.633 14.353 17.901 19.665 31.405 20.503 24.451 18.909 23.883 14.472

      同样可以看出,代码6是明显比代码5运行速度快的。

      当我们知道某一个节点的某些属性值是确定时,这时候我们可以将这个值保存在变量中,而不需要每次重新获取。否则当运行次数达到一定量后,会严重影响程序执行的速度。因为当第一次使用变量获取某个节点的值时,页面就会只reflow一次,并把这个值保存在内存中。下次程序需要时从内存中取就可以了。而代码5中则每次都沿着document去读取这些值,这些值虽然没有改变,但这些值是浏览器需要计算才能获得的,所以每次都会reflow一次。

      会导致reflow的属性有offsetLeft/Top、offsetHeight/Width、scrollTop/Left/Width/Height、clientTop/Left/Width/Height等。 

      养成使用这种方法的习惯,不但能提高程序性能,有时候还可以节省代码量,使程序更简洁。

  • 相关阅读:
    vue 动态生成 el-checkbox-group,动态绑定v-model的解决方法
    vue 弹窗内scrollTop取值为0的问题
    软件工程课程学习心得
    《软件工程》学习总结及获奖感言
    软件工程课程心得及小黄衫获奖感想
    Prometheus + Alertmanager 实现企业微信告警
    二进制安装Prometheus
    zabbix机器人告警配置流程
    c++不同平台崩溃解析总结
    c++跨平台开发技术总结
  • 原文地址:https://www.cnblogs.com/qilinge/p/4963072.html
Copyright © 2011-2022 走看看