浅析 innerHTML 性能优化的原理




昨天看了 lveyo老兄的"innerHTML的性能问题" 一文 http://lveyo.iteye.com/blog/182891

该文介绍了一篇老外的关于提高innerHTML性能的文章.

老外的方法非常的怪异且神奇.

很多朋友在惊叹之余 对于背后的原理非常感兴趣.
受hax的提醒, 我看了一下webkit的代码.在这里我将分析的结果分享出来

说的不一定对 还请大家多多拍砖.


浏览器在 el.innerHTML = newHTML 时所做的工作:

====================================
原始方法

1) 创建一个fragment(document碎片)
2) 将 newHTML 设置到 fragment 内部 (这里怎么设置的不必关心,反正不是用的innerHTML 呵呵)
3) 清除el下的所有子节点 ,  类似 el.removeChildren()
4) 将fragment加入到 el内, 类似 el.appendChild(fragment)


====================================
文章里的新方法

1)克隆el节点(不包含子节点),相当于
newEl=document.createElement(el.tagName);
然或将el的所有属性赋值给 newEl  (通过 el.getAttribute  newEl.setAttribute)

2) 创建一个fragment(document碎片)
3) 将 newHTML 设置到 fragment 内部 (这里怎么设置的不必关心,反正不是用的innerHTML 呵呵)
4) 清除 newEl 下的所有子节点 ,  类似 newEl.removeChildren()
5) 将 fragment 加入到 newEl 内, 类似 newEl.appendChild(fragment)
6) 用 fragment 替换 el. 相当于 el.parentNode.replaceChild(newEl, el);  

新方法看起来比原始方法更麻烦, 但是为什么速度会更快呢?

关键点就是在 新方法的步骤 4 5 6 .
首先看4:
newEl 是clone的el,但是没有子结点,所以removeChildren很快就返回.相当于没有执行.
而且就算newEL有子结点,由于newEl不是一个在dom树里的节点, 也省去了其中复杂的一步
Java代码 复制代码 收藏代码
  1. if (n->inDocument())  n->removedFromDocument();   
        if (n->inDocument())  n->removedFromDocument();
	

而 el.removeChildren 这个操作 相比之下自然要耗时很多.原因有三:removeChild操作比较复杂;el有子节点;el和el的子结点都在dom树内.


再来看5
newEl 和 fragment 本身都是脱离dom树独立存在的,这个操作速度也要比el.appendChild(fragment)快.

再来看6. 
6的操作就是 在el.parentNode中移除el,然后再在原始位置加入newEl. 这个步骤并没有速度优势.
但是 4 5 6这3个操作加起来,当el和newHTML足够复杂时,还是要比原始方法的 3 4 步更快


以上就是我的分析 有不对的地方 欢迎大家抛砖.
同时欢迎大家来贴一下 IE 和 ff的实现方式
原文地址:https://www.cnblogs.com/firstdream/p/5530048.html