一、DOM

1)DOM和JavaScript

文档对象模型(DOM)是一个独立于语言的,用于操作XML和HTML文档的程序接口(API)。

浏览器通常会把DOM和JavaScript独立实现。例如Chrome中使用Webkit的WebCore库渲染页面,用V8作为JavaScript引擎。

访问DOM天生就慢,将DOM和JavaScript比喻为两个岛屿,两处同行要收过桥费,ECMAScript访问DOM的次数越多,过桥费越贵,因此推荐的做法是尽可能减少过桥的次数。

2)性能测试

下图是对两段代码的性能测试,可在此处查看在线性能测试。

1. 第一段每一次循环都直接用DOM赋值

2. 第二段是先将内容缓存到局部变量中,最后使用一次DOM赋值。

测试结果以每秒钟执行测试代码的次数(Ops/sec)显示,这个数值越大越好。

除了这个结果外,同时会显示测试过程中的统计误差,以及相对最好的慢了多少(%),统计误差也是非常重要的指标。

二、选择器API

有时候为了得到需要的元素列表,需要组合调用getElementById等并遍历返回的节点,但这种繁密的过程效率低下。

使用CSS选择器是一种定位节点的便利途径,querySelectorAll就是DOM的原生方法。

//DOM组合APIvar elements = document.getElementById('menu').getElementsByTagName('a');//替换为简便的CSS选择器var elements = document.querySelectorAll('#menu a');

上面的例子不能体现效率的区别, 后面又改写了一个。在codepen中书写了一个例子,可以在线查看。

//从列表中选出CSS类是one的节点var elements = document.querySelectorAll('#menu a.one');var elements = document.getElementById('menu').getElementsByTagName('a'), list=[];for(var i=0, len=elements.length; i 
  

 

 

三、重绘与重排

在《CSS动画与JavaScript动画》中层提到过页面渲染的一般过程为JavaScript > 计算样式 > 布局 > 绘制 > 渲染层合并。

Layout(重排)和Paint(重绘)是整个环节中最为耗时的两环,所以我们尽量避免着这两个环节。

当DOM的变化影响了元素的几何属性(宽和高)将会发生重排(reflow);

完成重排后,浏览器会重新绘制受影响的部分到屏幕中,此过程为重绘(repaint)。

1)重排何时发生

1. 添加或删除可见的DOM元素

2. 元素位置改变

3. 元素尺寸改变(包括外边距、内边距、边框宽度、宽、高等属性)

4. 内容改变,例如文本改变或图片被不同尺寸的替换掉。

5. 页面渲染器初始化。

6. 浏览器窗口尺寸改变。

2)批量执行重排

下面代码看上去会重排3次,但其实只会重排1次,大多数浏览器通过队列化修改和批量显示优化重排版过程。

//渲染树变化的排队和刷新var ele = document.getElementById('myDiv');
ele.style.borderLeft = '1px';
ele.style.borderRight = '2px';
ele.style.padding = '5px';

但下列操作将会强迫队列刷新并要求所有计划改变的部分立刻应用:

offsetTop, offsetLeft, offsetWidth, offsetHeight 
scrollTop, scrollLeft, scrollWidth, scrollHeight 
clientTop, clientLeft, clientWidth, clientHeight 
getComputedStyle() (currentStyle in IE)(在 IE 中此函数称为 currentStyle)

像offsetHeight属性需要返回最新的布局信息,因此浏览器不得不执行渲染队列中的“待处理变化”并触发重排以返回正确的值。

对于尺寸坐标相关的信息可以参考《JavaScript中尺寸、坐标》。

3)最小化重绘和重排

1. cssText和class

cssText可以一次设置多个CSS属性。class也可以一次性设置,并且更清晰,更易于维护,但有前提条件,就是不依赖于运行逻辑和计算的情况。

// cssTextele.style.cssText = 'border-left: 1px; border-right: 2px; padding: 5px;';// classele.className = 'active';

在《JavaScript特性(attribute)、属性(property)和样式(style)》详细介绍了CSS相关的JS操作。

2. 批量修改DOM

2.1 隐藏元素display:none,应用修改,重新显示display:block。

2.2 使用文档片段fragment,在片段上操作节点,再拷贝回文档。

//文档片段(fragment)var fragment = document.createDocumentFragment();var li = document.createElement('li');
li.innerHTML = 'banana';
fragment.appendChild(li);
document.getElementById('fruit').appendChild(fragment);

2.3 将原始元素拷贝到一个脱离文档的节点中(例如position:absolute),修改副本,完成后再替换原始元素。

 

四、其它章节性能介绍

1)第一章 加载和执行