为什么要进行DOM优化?

  DOM对象本身也是一个js对象,所以严格来说,并不是操作这个对象慢,而是说操作了这个对象后,会触发一些浏览器行为,比如布局(layout)和绘制(paint)。

首先先说一些浏览器是怎么样把一个页面呈现出来的:

  一个浏览器有许多模块,其中负责呈现页面的是渲染引擎模块。

  这个过程大致如下:

  ·解析HTML,并生成一棵DOM tree
  ·解析各种样式并结合DOM tree生成一棵Render tree(渲染树)
  ·对Render tree的各个节点计算布局信息,比如box的位置与尺寸
  ·根据Render tree并利用浏览器的UI层进行绘制

注意:DOM tree和Render tree上的节点并非一一对应,比如一个"display:none"的节点就只会存在于DOM tree上,而不会出现在Render tree上,因为这个节点不需要被绘制。

Webkit的基本流程:

Gecko的基本流程:

  paint是一个耗时的过程,然而layout是一个更耗时的过程,我们无法确定layout一定是自上而下或是自下而上进行的,甚至一次layout会牵涉到整个文档布局的重新计算。
  关键来了:layout是肯定无法避免的,所以我们主要是要最小化layout的次数。

怎么样进行优化?

  前面提到,layout是肯定无法避免的,所以我们主要是要最小化layout的次数。在考虑如何最小化layout次数之前,要先了解什么时候浏览器会进行layout。
  layout(reflow)一般被称为布局,这个操作是用来计算文档中元素的位置和大小,是渲染前重要的一步。在HTML第一次被加载的时候,会有一次layout之外,js脚本的执行和样式的改变同样会导致浏览器执行layout,这也是本文的主要要讨论的内容。
  一般情况下,浏览器的layout是lazy的,也就是说:在js脚本执行时,是不会去更新DOM的,任何对DOM的修改都会被暂存在一个队列中,在当前js的执行上下文完成执行后,会根据这个队列中的修改,进行一次layout。[浏览器的layout为lazy模式,也就是说,并非每次我们对DOM进行修改时都会layout,而是将这些修改存储在一个队列中,在一定的情况下统一提交队列,进而实现layout操作。

  然而有时希望在js代码中立刻获取最新的DOM节点信息,浏览器就不得不提前执行layout,这是导致DOM性能问题的主因。

  如下的操作会打破常规,并触发浏览器执行layout:
    ·通过js获取需要计算的DOM属性[计算才能得到的属性]
    ·添加或删除DOM元素
    ·resize浏览器窗口大小
    ·改变字体
    ·css伪类的激活,比如:hover
    ·通过js修改DOM元素样式且该样式涉及到尺寸的改变

  所以我们要尽量减少上面layout的次数。

具体怎么做

1.批量读写
  当我们需要获取某一属性,这一属性需要计算才能得到,并且队列中存在尚未提交的DOM修改操作,则此时,DOM修改操作的队列将会被提交。
为了提高效率,减少更新render tree的次数,可以先统一读取属性,然后统一修改DOM,这样,就可以减少更新render tree的次数。

例如:

var h1 = element1.clientHeight;
element1.style.height = (h1 * ) + 'px';
var h2 = element2.clientHeight;
element2.style.height = (h2 * ) + 'px';
var h3 = element3.clientHeight;
element3.style.height = (h3 * 2) + 'px';

clientHeight,这个属性是需要计算得到的,于是就会触发浏览器的一次layout。

优化后:

var h1 = element1.clientHeight;
var h2 = element2.clientHeight;
var h3 = element3.clientHeight; element1.style.height = (h1 * ) + 'px';
element2.style.height = (h2 * ) + 'px';
element3.style.height = (h3 * ) + 'px';

2.虚拟结点
当我们需要对DOM做出大量修改时,可以先创建一个虚拟结点,将所有修改附加在该节点,最后将该虚拟节点一次性提交给在render tree上存在的结点,则相当于只提交了一次修改操作。

var fragment = document.createDocumentFragment();
for (var i=; i < items.length; i++){
var item = document.createElement("li");
item.appendChild(document.createTextNode("Option " + i);
fragment.appendChild(item);
}
list.appendChild(fragment);

3.动画的每一帧都会导致layout,这是无法避免的,但是为了减少动画带来的layout的性能损失,可以将动画元素绝对定位,这样动画元素脱离文本流,layout的计算量会减少很多。

未完待续...

参考:

http://kb.cnblogs.com/page/534571/

--2017年3月06号补充:

前端开发者应知必会:浏览器是如何渲染网页的

关键字:层叠样式表模型CSSOM、重绘Repaint、回流Reflow、强制回流

DOM的相关优化的更多相关文章

  1. IT蓝豹强烈推荐:符合1-2年工作经验,开发中的难点及相关优化:

    IT蓝豹强烈推荐:符合1-2年工作经验,开发中的难点及相关优化: IT蓝豹 ------------------> sqlite数据库版本升级 1.sqlite升级步骤: 1.自己写一个类继承自 ...

  2. MySQL的Innodb缓存相关优化

    MySQL的Innodb缓存相关优化 INNODB 状态的部分解释 通过 命令 SHOW STATUS LIKE  'Innodb_buffer_pool_%' 查看  Innodb缓存使用率  (I ...

  3. (转) Delete/Truncate删除,释放表空间、降低高水位线、resize释放磁盘空间相关优化

    硬盘空间不足,打算删除数据库中的多余数据,但删除数据后,硬盘硬盘空间不能释放.[delete后用:alter table table_name move    truncate后用:alter tab ...

  4. 阿里云 RTC QoS 屏幕共享弱网优化之若干编码器相关优化

    屏幕共享是视频会议中使用频率最高的功能之一,但在实际场景中用户所处网络环境复杂,常遇到丢包或者拥塞的情况,所以如何优化弱网环境下的用户体验也成为了音视频通信中重要的一环.本文主要分享阿里云 RTC Q ...

  5. django学习-27.admin管理后台里:对列表展示页面的数据展示进行相关优化

    目录结构 1.前言 2.完整的操作步骤 2.1.第一步:查看ModelAdmin类和BaseModelAdmin类的源码 2.2.第二步:查看表animal对应的列表展示页面默认的数据展示 2.3.第 ...

  6. DOM解析和优化

    DOM解析 1. css不会阻塞DOM解析(DOM Tree),但会阻塞DOM渲染(css Tree + DOM Tree -> render Tree )2. JS阻塞DOM解析,但浏览器会预 ...

  7. eclipse中build workspace的相关优化

    网上流传的各种的eclipse的调优的方法都大同小异,但是调优的基本上针对eclipse或者myclipse的本身,比如关掉validate和启动项,文件拼写,和自动构建等,调过之后,等个eclips ...

  8. 原生JS中DOM节点相关API合集

    节点属性 Node.nodeName //返回节点名称,只读 Node.nodeType //返回节点类型的常数值,只读 Node.nodeValue //返回Text或Comment节点的文本值,只 ...

  9. (转)Javascript的DOM操作 - 性能优化

    转载:https://my.oschina.net/blogshi/blog/198910 摘要: 想稍微系统的说说对于DOM的操作,把Javascript和jQuery常用操作DOM的内容归纳成思维 ...

随机推荐

  1. Android之Proguard语法

    -include {filename} 从给定的文件中读取配置参数 -basedirectory {directoryname} 指定基础目录为以后相对的档案名称 -injars {class_pat ...

  2. 日志分析 第一章 ELK介绍

    1 ELK各组件介绍? ELK Stack是elasticsearch.logstash.kibana是三个开源软件的组合, fielbeat是一个轻量级日志收集工具,类似于Linux系统中tail ...

  3. php返回json数据中文显示的问题

    PHP5.4版本,已经给Json新增了一个选项: JSON_UNESCAPED_UNICODE.加上这个选项后,就不会自动把中文编码了. echo json_encode("厦门" ...

  4. host,nslookup,dig 命令安装

    host,nslookup,dig依赖bind包,所以先看一下系统有没有bind包 命令如下:rpm -qa |grep bind 如果没有或者版本太低请升级安装 命令是:yum install bi ...

  5. ubuntu下安装TexLive和Texmaker

    也可以参考ubuntu14.04配置中文latex完美环境(texlive+texmaker+lyx) 设置中文字体的时候参考ubuntu 下安装 texlive 并设置 ctex 中文套装 1.首先 ...

  6. Android学习笔记——Handler(一)

    使用Handler管理线程(转) 步骤: 1. 申请一个Handler对象 Handler handler = new Handler(); 2. 创建一个线程 {继承Thread类或者实现Runna ...

  7. 配置git密钥,然后新建仓库

    Generating SSH keys (打开下面的链接) https://help.github.com/articles/generating-ssh-keys/ 完成配置后 开始在github上 ...

  8. 2015 前端[JS]工程师必知必会

    2015 前端[JS]工程师必知必会 本文摘自:http://zhuanlan.zhihu.com/FrontendMagazine/20002850 ,因为好东东西暂时没看懂,所以暂时保留下来,供以 ...

  9. TCP的三次握手与四次分手

    TCP的位置 TCP工作在网络OSI的七层模型中的第四层——Transport层,IP在第三层——Network层,ARP在第二层——Data Link层: 在第二层上的数据,我们把它叫Frame,在 ...

  10. 为什么要使用class.forname在DriverManager.getConnection之前

    JDBC在getConnection之前为什么要调用Class.forName 获取一个数据库连接的通用模板如下: String driver = "oracle.jdbc.OracleDr ...