DOM优化

最后更新于:2022-04-01 04:51:42

## `DOM`优化 > * 优化节点修改。 > > > * 使用`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属性缓存在一个本地变量中,这样就能大幅度的提高循环的效率。
';