高性能javascript笔记:浏览器中DOM操作的性能优化(二)

摘要:
关于浏览器中DOM操作的性能优化,访问和修改DOM元素对性能的影响和优化方案已在之前的博客文章“浏览器中的DOM操作性能优化(I)”中描述。浏览器下载完所有HTML标记及其组件后,浏览器将解析文件并创建两个内部数据结构:1.DOM树:表示页面的结构2.RenderTree:表示DOM树在呈现树中的显示方式。每个DOM节点至少有一个对应的节点。

  关于浏览器中DOM操作的性能优化,在上一篇博文《浏览器中DOM操作的性能优化(一)》中已经阐述了访问和修改DOM元素对性能的影响及优化方案。这次我们就来说一下关于页面的重绘和重排版问题。

  当浏览器下载完所有的HTML标签和其组件(Javascript,css,图片等)后,浏览器就会解析文件并创建两个内部数据结构:
  1、DOM Tree :表示页面的结构
  2、Render Tree :表示DOM树如何显示

  在渲染树仲,每个DOM节点(隐藏的节点除外)都有至少一个相对应的节点。渲染树的节点被称为“盒”,符合CSS定义的盒子模型——一个具有填充(padding)、边框(border)、边距(margin)和位置(position)的盒子。一旦DOM树和渲染树构造完毕,浏览器就可以显示(绘制)页面上的元素。

  当DOM的元素几何属性(宽和高)改变的时候,浏览器就是重新计算元素的几何属性,而其它元素的几何属性和位置也可能会因此受到影响,对应的渲染树部分因此失效,浏览器就不得不重构渲染树,这个过程就叫做重排版。重排版完成时,浏览器会在一个重绘进程中绘制屏幕上受影响的部分。而如果没有改变元素的几何属性(如仅改变元素的背景),元素的布局没有受到影响,这个过程就叫做重绘。下述情况中会发生重排版:

  1. 添加或删除可见的元素
  2. 元素的位置改变
  3. 元素的尺寸改变
  4. 元素的内容改变
  5. 浏览器窗口大小改变

  调用某些方法或访问某些属性也会引发重排版,因为需要计算布局信息,所以浏览器不得不运行渲染队列中待改变的项目并重新排版以返回正确的值。所以当要用到下列的属性或方法时,最好用局部变量缓存它们

  1. offsetTop、offsetLeft、offsetWidth、offsetHeight
  2. scrollTop、scrollLeft、scrollWidth、scrollHeight
  3. clientTop、clientLeft、clientWidth、clientHeight
  4. document.defaultView.getComputedStyle() (IE中对应的元素属性是currentStyle)

  既然重绘和重排版会带来性能影响,我们就应该避免次情况发生的次数。

  修改style属性

  考虑下面的这个列子:

var el = docuemnt.getElementById("mydiv");
el.style.borderLeft = "1px";
el.style.margin = "5px";
el.style.padding = "5px";

  可以优化成如下代码:

var el = document.getElementById("mydiv");
el.style.cssText = ";border:1px;margin:5px;padding:5px";//注意前面有个分号,避免覆盖之前的样式

  DOM元素的批量修改

  当你需要对DOM元素进行多次修改时,可通过以下的步骤减少重绘和重排版的次数:

  1. 从文档流中移除该DOM元素(引发重排版)
  2. 对该元素进行多次修改(如果其它两步,则每一次修改都会导致重排版)
  3. 将元素带回文档中显示(引发重排版)

  有二种方法可以将DOM元素从文档流中移除:

  1. 隐藏元素,进行修改,然后再显示
  2. 新创建或克隆节点,进行修改,然后覆盖原始的DOM元素

  下面就举个列子说明(更新列表):

  HTML code:

<ul id="mylist">
    <li><a href="http://www.baidu.com">baidu</a></li>
    <li><a href="http://www.google.com.hk">google</a></li>
</ul>

  Javascript code:

//要添加的数据
var data = [
    {
        name:"cnblogs",
        url:"http://www.cnblogs.com/"
    },
    {
        name:"leolai",
        url:"http://www.cnblogs.com/leolai/"
    }
];

//创建一个通用的函数,用于将数据添加到指定的列表中
function appendDataToList(targetElement, data){
    var a, li, item;
    for(var i=0,len=data.length; i<len; i++){
        item = data[i];
        a = document.createElement("a");
        a.src = item.url;
        a.appendChild(document.createTextNode(item.name));
        
        li = document.createElement("li");
        li.appendChild(a);
        targetElement.appendChild(li);
    }
}

//如果不理会重排版问题,将数据更新到列表中最简单的方法如下
var ul = document.getElementById("mylist");
appendDataToList(ul,data);
//使用这个方法,当data中每个项目追加到ul中都会导致重排版
//所以根据上面提到的优化方法,可修改成如下代码

//
修改一:先隐藏,再修改,最后显示 var ul = document.getElementById("mylist"); ul.style.display = "none"; appendDataToList(ul,data); ul.style.display = "block"; //修改二:利用文档片段做一次性更新(推荐使用) var fragment = document.createDocumentFragment(); appendDataToList(fragment,data); document.getElementById("mylist").appendChild(fragment); //修改三:克隆,修改副本,覆盖 var ul = document.getElementById("mylist"); var clone = ul.cloneNode(true); appendDataToList(clone,data); ul.parentNode.replaceChild(clone,ul);

  另外,我们经常在网页上做一些动画效果,对于这些动画元素应使用绝对定位,因为绝对定位不存在于文档流,所以它的改变不会影响到页面的布局

  还有,如果大量元素使用了:hover会降低反应速度。此问题在ie8中更为显著。

免责声明:文章转载自《高性能javascript笔记:浏览器中DOM操作的性能优化(二)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇C#编程总结(二)多线程基础Vue 计数器下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

C#数组段ArraySegment&amp;lt;T&amp;gt;的使用

//数组段ArraySegment<T>的使用 using System; using System.Collections; using System.Collections.Generic; using System.Text; using System.Linq; namespace ss { class Program...

logstash5安装并实现mariadb数据写入到elasticsearch

java环境这里默认安装了 ,一般源码安装,这里就不说了 一、安装logstash 安装logstash可以用yum安装,也可以用源码安装: yum安装: 1.导入GPG: rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch 2.创建repo文件,vim /etc/yum.repo...

微信小程序开发——setData的使用技巧

前言: 之前使用 setData ,一直都是作为给变量赋值,感觉比起vue给data中的变量的赋值还是有点麻烦的。 最近项目不太紧张,为了提高小程序的开发效率及提升小程序开发的能力,又重新的通读了下小程序的开发文档。发现 setData 还有一个非必填的参数 callback——setData引起的界面更新渲染完毕后的回调函数,通过这个回调函数,可以在更新...

封装两个简单的Jquery组件

Jquery给我们提供了很大的方便,我们把他看成是一个公共库,以致在这个公共库上延伸出了很多Jquery插件;在项目过程中,有些插件总是不那么令人满意; 主要说两个项目用途: 1、 遮罩层,跟一般的遮罩层不一样,我需要实现的是对某一个元素进行局部遮罩; 2、 冒泡提示,网上有很多,我需要的只是一种在页面指定位置弹出来的一个静止定位的div而已;两个就自己了...

elasticsearch 性能优化

转载: https://www.cnblogs.com/jajian/p/10465519.html 硬件选择 Elasticsearch(后文简称 ES)的基础是 Lucene,所有的索引和文档数据是存储在本地的磁盘中,具体的路径可在 ES 的配置文件../config/elasticsearch.yml中配置,如下: # ---------------...

ABAP-AES加解密

https://blogs.sap.com/2019/08/26/aes-encryption-in-abap/ https://github.com/Sumu-Ning/AES https://blog.csdn.net/u012232542/article/details/103184183 介绍 最近,我们的组织要求对从 SAP 到外部系统的所有数据...