优化节点修改。
使用
cloneNode
在外部更新节点然后再通过replace
与原始节点互换。var orig = document.getElementById('container'); var clone = orig.cloneNode(true); var list = ['foo', 'bar', 'baz']; var content; for (var i = 0; i < list.length; i++) { content = document.createTextNode(list[i]); clone.appendChild(content); } orig.parentNode.replaceChild(clone, orig);优化节点添加
多个节点插入操作,即使在外面设置节点的元素和风格再插入,由于多个节点还是会引发多次reflow。
优化的方法是创建
DocumentFragment
,在其中插入节点后再添加到页面。
如
JQuery
中所有的添加节点的操作如append
,都是最终调用DocumentFragment
来实现的,createSafeFragment(document) { var list = nodeNames.split( "|" ), safeFrag = document.createDocumentFragment(); if (safeFrag.createElement) { while (list.length) { safeFrag.createElement( list.pop(); ); }; }; return safeFrag; };优化
CSS
样式转换。如果需要动态更改CSS样式,尽量采用触发reflow次数较少的方式。
如以下代码逐条更改元素的几何属性,理论上会触发多次
reflow
。element.style.fontWeight = 'bold' ; element.style.marginLeft= '30px' ; element.style.marginRight = '30px' ;可以通过直接设置元素的
className
直接设置,只会触发一次reflow
。element.className = 'selectedAnchor' ;减少
DOM
元素数量
在
console
中执行命令查看DOM
元素数量。`document.getElementsByTagName( '*' ).length`正常页面的
DOM
元素数量一般不应该超过1000
。DOM
元素过多会使DOM
元素查询效率,样式表匹配效率降低,是页面性能最主要的瓶颈之一。DOM
操作优化。
DOM
操作性能问题主要有以下原因。
DOM
元素过多导致元素定位缓慢。- 大量的
DOM
接口调用。
JAVASCRIPT
和DOM
之间的交互需要通过函数API
接口来完成,造成延时,尤其是在循环语句中。DOM
操作触发频繁的reflow(layout)
和repaint
。layout
发生在repaint
之前,所以layout相对来说会造成更多性能损耗。
reflow(layout)
就是计算页面元素的几何信息。repaint
就是绘制页面元素。- 对
DOM
进行操作会导致浏览器执行回流reflow
。- 解决方案。
- 纯
JAVASCRIPT
执行时间是很短的。- 最小化
DOM
访问次数,尽可能在js端执行。- 如果需要多次访问某个
DOM
节点,请使用局部变量存储对它的引用。- 谨慎处理
HTML
集合(HTML
集合实时连系底层文档),把集合的长度缓存到一个变量中,并在迭代中使用它,如果需要经常操作集合,建议把它拷贝到一个数组中。- 如果可能的话,使用速度更快的API,比如
querySelectorAll
和firstElementChild
。- 要留意重绘和重排。
- 批量修改样式时,
离线
操作DOM
树。- 使用缓存,并减少访问布局的次数。
- 动画中使用绝对定位,使用拖放代理。
- 使用事件委托来减少事件处理器的数量。
- 优化
DOM
交互 >在JAVASCRIPT
中,DOM
操作和交互要消耗大量时间,因为它们往往需要重新渲染整个页面或者某一个部分。
- 最小化
现场更新
。
- 当需要访问的
DOM
部分已经已经被渲染为页面中的一部分,那么DOM
操作和交互的过程就是再进行一次现场更新
。
现场更新
是需要针对现场
(相关显示页面的部分结构)立即进行更新,每一个更改(不管是插入单个字符还是移除整个片段),都有一个性能损耗。- 现场更新进行的越多,代码完成执行所花的时间也越长。
- 多使用
innerHTML
。
- 有两种在页面上创建
DOM
节点的方法:
- 使用诸如
createElement()
和appendChild()
之类的DOM
方法。- 使用
innerHTML
。
- 当使用
innerHTML
设置为某个值时,后台会创建一个HTML
解释器,然后使用内部的DOM
调用来创建DOM
结构,而非基于JAVASCRIPT
的DOM
调用。由于内部方法是编译好的而非解释执行,故执行的更快。 >对于小的DOM
更改,两者效率差不多,但对于大的DOM
更改,innerHTML
要比标准的DOM
方法创建同样的DOM
结构快得多。回流
reflow
。
发生场景。
- 改变窗体大小。
- 更改字体。
- 添加移除stylesheet块。
- 内容改变哪怕是输入框输入文字。
- CSS虚类被触发如 :hover。
- 更改元素的className。
当对DOM节点执行新增或者删除操作或内容更改时。
动态设置一个style样式时(比如element.style.width="10px")。
- 当获取一个必须经过计算的尺寸值时,比如访问offsetWidth、clientHeight或者其他需要经过计算的CSS值。
解决问题的关键,就是限制通过DOM操作所引发回流的次数。
在对当前DOM进行操作之前,尽可能多的做一些准备工作,保证N次创建,1次写入。
在对DOM操作之前,把要操作的元素,先从当前DOM结构中删除:
通过removeChild()或者replaceChild()实现真正意义上的删除。
- 设置该元素的display样式为“none”。
每次修改元素的style属性都会触发回流操作。
element.style.backgroundColor = "blue";
使用更改
className
的方式替换style.xxx=xxx
的方式。使用
style.cssText = '';
一次写入样式。避免设置过多的行内样式。
添加的结构外元素尽量设置它们的位置为
fixed
或absolute
。避免使用表格来布局。
- 避免在
CSS
中使用JavaScript expressions(IE only)
。将获取的
DOM
数据缓存起来。这种方法,对获取那些会触发回流操作的属性(比如offsetWidth
等)尤为重要。- 当对HTMLCollection对象进行操作时,应该将访问的次数尽可能的降至最低,最简单的,你可以将length属性缓存在一个本地变量中,这样就能大幅度的提高循环的效率。