我们知道,对DOM的操作都是非常的耗性能的,那么为什么会耗性能呢?
     文档对象模型(DOM)是一个独立于语言的,使用 XML和 HTML 文档操作的应用程序接口(API)。在浏览器中,主要与 HTML 文档打交道,在网页应用中检索 XML 文档也很常见。DOM APIs 主要用于访问这些文档中的数据。尽管 DOM 是与语言无关的 API,在浏览器中的接口却是以 JavaScript 实现的。客户端大多数脚本程序与文档打交道,DOM 就成为 JavaScript 代码日常行为中重要的组成部分。 
一、重绘和重排版        
        当浏览器加载完所有页面 HTML标签,JavaScript,CSS之后,它开始解析文件并创建两个内部数据结构: 一棵 DOM 树表示页面结构 ;一棵渲染树表示 DOM 节点如何显示。渲染引擎首先解析HTML文档,转换为一棵DOM树,此为第一步。接下来不管是内联式,外联式还是嵌入式引入的CSS样式也会被解析,渲染出另 外一棵用于渲染DOM树的树-渲染树(render tree) ,渲染树包含带有颜色,尺寸等显示属性的矩形,这些矩形的顺序与显示顺序一致。渲染树中为每个需要显示的DOM树节点存放至少一个节点(隐藏 DOM 元素在渲染树中没有对应节)。渲染树上的节点称为“框”或者“盒”,符合 CSS 模型的定义,将页面元素看作一个具有填充、边距、框和位置的盒。一旦 DOM 树和渲染树构造完毕,浏览器就可以显示(绘制)页面上的元素了。 
        当 DOM 改变影响到元素的几何属性(宽和高)——例如改变了边框宽度或在段落中添加文字,将发生一系列后续动作——浏览器需要重新计算元素的几何属性,而且其他元素的几何属性和位置也会因此改变受到影响。浏览器使渲染树上受到影响的部分失效,然后重构渲染树。这个过程被称作重排版。重排版完成时,浏览器在一个重绘进程中重新绘制屏幕上受影响的部分。 
        不是所有的 DOM 改变都会影响几何属性。例如,改变一个元素的背景颜色不会影响它的宽度或高度。在这种情况下,只需要重绘(不需要重排版),因为元素的布局没有改变。 重绘和重排版是负担很重的操作,可能导致网页应用的用户界面失去响应。那么,什么时候会发生重排版呢?
        1、添加或删除可见的 DOM 元素 ;
        2、元素位置改变 ;
        3、元素尺寸改变(因为边距,填充,边框宽度,宽度,高度等属性改变);
        4、内容改变,例如,文本改变或图片被另一个不同尺寸的所替代 ;
        5、最初的页面渲染;
        6、浏览器窗口改变尺寸。
根据改变的性质,渲染树上或大或小的一部分需要重新计算。某些改变可导致重排版整个页面:例如,当一个滚动条出现时。 
         因为计算量与每次重排版有关,大多数浏览器通过队列化修改和批量显示优化重排版过程。然而,你可能(经常不由自主地)强迫队列刷新并要求所有计划改变的部分立刻应用。获取布局信息的操作将导致刷新队列动作,这意味着使用了下面这些方法: 
 • offsetTop, offsetLeft, offsetWidth, offsetHeight 
• scrollTop, scrollLeft, scrollWidth, scrollHeight 
• clientTop, clientLeft, clientWidth, clientHeight 
• getComputedStyle() (currentStyle in IE)(在 IE 中此函数称为 currentStyle) 
布局信息由这些属性和方法返回最新的数据, 所以浏览器不得不运行渲染队列中待改变的项目并重新排版以返回正确的值。
二、最小化重绘和重排版
var el = document.getElementById('mydiv');
el.style.borderLeft = '1px';
el.style.borderRight = '2px';
el.style.padding = '5px';
这里改变了三个风格属性,每次改变都影响到元素的几何属性。在这个糟糕的例子中,它导致浏览器重排版了三次。大多数现代浏览器优化了这种情况只进行一次重排版,但是在老式浏览器中,或者同时有一个分离的同步进程(例如使用了一个定时器),效率将十分低下。如果其他代码在这段代码运行时查询布局信息,将导致三次重布局发生。而且,此代码访问 DOM 四次,可以被优化。   一个达到同样效果而效率更高的方法是:将所有改变合并在一起执行,只修改 DOM 一次。可通过使用cssText 属性实现: 
var el = document.getElementById('mydiv');
el.style.cssText = 'border-left: 1px; border-right: 2px; padding: 5px;';
     另一个一次性改变风格的办法是修改 CSS 的类名称,而不是修改内联风格代码。这种方法适用于那些风格不依赖于运行逻辑,不需要计算的情况。改变 CSS 类名称更清晰,更易于维护;它有助于保持脚本免除显示代码,虽然它可能带来轻微的性能冲击,因为改变类时需要检查级联表。 

var el = document.getElementById('mydiv');
el.className = 'active';
三、批量修改 DOM 
        当你需要对 DOM 元素进行多次修改时,你可以通过以下步骤减少重绘和重排版的次数:
        1、从文档流中摘除该元素 ;
        2、对其应用多重改变;
        3、将元素带回文档中 。
此过程引发两次重排版——第一步引发一次,第三步引发一次。如果你忽略了这两个步骤,那么第二步中每次改变都将引发一次重排版。 
有三种基本方法可以将 DOM 从文档中摘除:
        1、隐藏元素,进行修改,然后再显示它;
var ul = document.getElementById('mylist');
ul.style.display = 'none';
appendDataToElement(ul, data);
ul.style.display = 'block';
        2、使用一个文档片断在已存 DOM 之外创建一个子树,然后将它拷贝到文档中;

var fragment = document.createDocumentFragment();
appendDataToElement(fragment, data);
document.getElementById('mylist').appendChild(fragment);
        3、将原始元素拷贝到一个脱离文档的节点中,修改副本,然后覆盖原始元素。 

var old = document.getElementById('mylist');
var clone = old.cloneNode(true);
appendDataToElement(clone, data);
old.parentNode.replaceChild(clone, old);

ps:以上内容总结于《高性能javascript编程》

高性能javascript学习总结(2)--DOM编程的更多相关文章

  1. 高性能javascript学习笔记系列(3) -DOM编程

    参考 高性能javascript 文档对象模型(DOM)是独立于语言的,用于操作XML和HTML文档的程序接口API,在浏览器中主要通过DOM提供的API与HTML进行交互,浏览器通常会把DOM和ja ...

  2. javascript学习 真正理解DOM脚本编程技术背后的思路和原则

    本文学习来源于<javascriptDOM编程艺术>仅作笔记 学会怎样才能利用DOM脚本编程技术以一种既方便自己更体贴用户的方式去充实和完善你们的网页. 循序渐进:从最核心的内容开始,逐步 ...

  3. 高性能javascript学习笔记系列(5) -快速响应的用户界面和编程实践

    参考高性能javascript 理解浏览器UI线程  用于执行javascript和更新用户界面的进程通常被称为浏览器UI线程  UI线程的工作机制可以理解为一个简单的队列系统,队列中的任务按顺序执行 ...

  4. 高性能javascript学习笔记系列(1) -js的加载和执行

    这篇笔记的内容主要涉及js的脚本位置,如何加载js脚本和脚本文件执行的问题,按照自己的理解结合高性能JavaScript整理出来的 javascript是解释性代码,解释性代码需要经历转化成计算机指令 ...

  5. JavaScript(三)-- DOM编程

    JavaScript编程中最基本的就是DOM编程,DOM是 Document Object Model文本对象模型,就是对DOM对象进行编程的过程. Java语言和Js都有针对于DOM的编程,两者类似 ...

  6. 高性能javascript学习总结(3)--数据访问

    在 JavaScript 中,数据存储位置可以对代码整体性能产生重要影响.有四种数据访问类型:直接量,变量,数组项,对象成员.         直接量仅仅代表自己,而不存储于特定位置. JavaScr ...

  7. 高性能javascript学习笔记系列(6) -ajax

    参考 高性能javascript javascript高级程序设计 ajax基础  ajax技术的核心是XMLHttpRequest对象(XHR),通过XHR我们就可以实现无需刷新页面就能从服务器端读 ...

  8. 高性能javascript学习笔记系列(4) -算法和流程控制

    参考高性能javascript for in 循环  使用它可以遍历对象的属性名,但是每次的操作都会搜索实例或者原型的属性 导致使用for in 进行遍历会产生更多的开销 书中提到不要使用for in ...

  9. 高性能javascript学习笔记系列(2)-数据存取

    参考 高性能javascript Tom大叔深入理解javascript系列 相关概念 1.执行上下文   当控制器转到ecmascript可执行代码的时候,就会进入一个执行上下文,执行上下文是以堆栈 ...

随机推荐

  1. 【DB2】根据映射表映射出结果

    第一步:创建语法 CREATE TABLE OLIVER_MAP(ID INT,COM_TYPE VARCHAR(100),COM_NAME VARCHAR(100),SR_UP DECIMAL(18 ...

  2. Oracle 创建表空间、临时表空间、创建用户并指定表空间、授权,删除用户及表空间

    /* 说明:若已经存在相应的用户和表空间,则需要先删除相应的用户和表空间 然后再全部重新建立 */ --删除用户 drop user USERNAME cascade; --删除表空间 drop ta ...

  3. 企业级监控工具Cacti安装配置全过程

      Cacti 在英文中的意思是仙人掌的意思,Cacti是一套基于PHP,MySQL,SNMP及RRDTool开发的网络流量监测图形分析工具.它通过 snmpget来获取数据,使用 RRDtool绘画 ...

  4. DNS原理及其解析过程【精彩剖析】

    DNS原理及其解析过程[精彩剖析] 2012-03-21 17:23:10 标签:dig wireshark bind nslookup dns 原创作品,允许转载,转载时请务必以超链接形式标明文章 ...

  5. C#制作ActiveX控件中调用海康SDK的问题

    事情是这样的,有一台海康威视的摄像头,客户需要一个ActiveX控件嵌入到网页中,通过点击按钮开始录制和结束录制来进行视频的录制和保存,关于海康摄像头的二次开发在此就不多说了,可以参考SDK中的说明. ...

  6. Docker镜像Export导出和Import导入

    在使用Docker时最头痛的无非无法获取仓库镜像,我们可以通过Export导出镜像备份,通过import导入镜像.导出镜像是通过容器进行导出,下面来看镜像对应的容器: root@default:~# ...

  7. listView的异步加载数据

    1 public class MainActivity extends Activity { 2 3 private ListView listView; 4 private ArrayList< ...

  8. 【机器学习详解】SMO算法剖析(转载)

    [机器学习详解]SMO算法剖析 转载请注明出处:http://blog.csdn.net/luoshixian099/article/details/51227754 CSDN−勿在浮沙筑高台 本文力 ...

  9. warning: push.default is unset; its implicit value is changing in Git 2.0 from 'matching' to 'simple'.

    'matching'参数是 git 1.x 的默认行为,其意是如果你执行 git push 但没有指定分支,它将 push 所有你本地的分支到远程仓库中对应匹配的分支. 而 Git 2.x 默认的是 ...

  10. Ionic项目打包安卓APK

    之前用Ionic+Angular做了几个小应用Demo,现在用其中一个做实验试下打包安卓的APK安装包.(备注:我用的应用demo是之前博客里写的汇率的Demo,不清楚的同学可以查哈~) 我是用ion ...