Skip to content

对于 DOM 的性能优化,主要是以下几点

  1. ECMAScript 与 DOM 在浏览器是独立实现的,所以通过 JS 去访问 DOM 都是需要过桥费的,会有很大的性能损耗。

最小化 DOM 的访问次数,尽量在 JS 端处理

优化的方法

  • 缓存常用的 DOM
  • innerHTML 与 createElement() 相差无几
  • 复杂的 DOM 操作 使用 document.createDocumentFragement() 虚拟上下文
  • el.cloneNode() 克隆节点操作 完成后再 replaceChild()
  1. 如果需要多次访问某个 DOM 节点,请使用局部变量存储起来。

  2. 小心处理 HTML 集合概念(HTML 集合是实时的),所以

我们常用的集合有哪些?

  • NodeList
  • NamedNodeMap
  • HTMLCollection

优化的方法

  • 把集合的长度缓存到一个局部变量中。
  • 如果需要经常操作集合,请拷贝到一个数组中。
  1. 尽量使用速度更快的 API,如 querySelector() querySelectorAll()。 不要 document.getElementById("id").getElementsByTagName('li')这种。

  2. 留意重绘与重排。批量修改样式时,离线操作 DOM,使用缓存,并减少访问布局信息的次数。

  3. 动画中使用绝对定位,使用拖放代理。

  4. 使用事件委托来减少事件处理器的数量

// 1. ECMAScript 与 DOM 在浏览器是独立实现的,所以通过 JS 去访问 DOM 都是需要过桥费的,会有很大的性能损耗。 // 1.1 最小化 DOM 的访问次数,尽量在 JS 端处理 for(var i =5000;i>0;i--){ document.getElementById('id1').innerHTML += 'a'; } // 我们需要修改的地方就有 // 1. 不要频繁的访问 DOM,多次访问 DOM 缓存 DOM 对象。 var $id1 = document.getElementById('id1'); for(var i =5000;i>0;i--){ $id1.innerHTML += 'a'; } // 第二 不要频繁的去操作 DOM var $id1 = document.getElementById('id1'); var str = ''; for(var i =5000;i>0;i--){ str += 'a'; } $id1.innerHTML = str;

  1. 小心处理 HTML 集合概念(HTML 集合是实时的),所以 方法 document.getElementsByTagName() document.getElementsByClassName() document.getElementsByName() 属性 document.images,document.links, 元素的属性 el.attributes el.classList 例子: // 1. 死循环 var allDivs = document.getElementsByTagName('div'); for(var i =0;i<allDivs.length;i++){ document.body.appendChild(document.createElement('div')); }

// 2. 因为集合是实时的,所以我们每次读取 length 的时候,都需要重新查询,所以读取集合的 length 比数组的 length 慢得多。 // 第一步: 缓存 length var allDivs = document.getElementsByTagName('div'), divLength = addDivs.length; for(var i=divLength-1;i>=0;i--){ document.body.appendChild(document.createElement('div')); }

// 当我们需要对集合的每一个元素进行操作的时候,特别是大数据量的时候,最好每次缓存其 DOM var allDivs = document.getElementsByTagName('div'), divLength = addDivs.length cacheEl = null; var name = ''; for(var i=divLength-1;i>=0;i--){ cacheEl = allDivs[i]; name = cacheEl.nodeName; name = cacheEl.nodeType; name = cacheEl.nodeValue; }

// 4. 尽量使用速度更快的 API var el = document.getElementById("id").getElementsByTagName('li'); //这种最好使用 var el = document.querySelector('#id li')

  1. 留意重绘与重排。批量修改样式时,离线操作 DOM,使用缓存,并减少访问布局信息的次数。

什么是重排 当浏览器中的元素几何属性(宽高),位置发生了改变,浏览器需要使受影响的元素失效,重新构造渲染树。 什么是重绘 当元素的颜色,背景色等不影响宽高、位置的属性改变了,需要浏览器重新绘制一下这个元素就行。

重排产生情况

  1. 添加或者删除可见的 DOM 元素。
  2. 元素的位置发生改变。
  3. 元素的尺寸发生改变(外边距,边框,内边距,内容,宽高)
  4. 元素内容发生了修改。 文本修改 图片修改
  5. 页面渲染初始化
  6. 浏览器的窗口尺寸改变

浏览器通过队列话的方式去批量执行重排,但有些会强制刷新队列,并立即执行。(获取布局信息) offsetTop,offsetLeft,offsetWidth,offsetHeight scrollTop,scrollLeft,scrollWidth,scrollHeight clientTop,clientLeft,clientWidth,clientHeight getComputedStyle() currentStyle

怎么优化

  1. 样式的处理 通过 cssText 批量处理 style, className 批量处理 class
  2. 操作 DOM
  3. 使元素脱离文档流-> 处理元素 -> 添加回文档流 display:none; 文档片段 document.createDocumentFragment() cloneNode
  4. 获取布局信息

不建议
el.offsetTop = el.offsetTop + 2 + 'px'; 建议 var top = el.offsetTop; el.offsetTop = top + 1 + 'px';

  1. 动画问题 如我们常有的展开与折叠元素,这个就有大量的重排 解决方式 先让其脱离文档流,然后在添加入文档流中