一、故事背景
这周一看《高程3》中,“11.3.6 插入标记”章节中的第4部分,“内存与性能”,里面有谈到关于innerHTML的性能问题。
一般来说,在插入大量新HTML标记时,使用innerHTML属性与通过多次DOM操作先创建节点再指定它们之间的关系相比,效率要高得多。这是因为在设置innerHTML或outerHTML时,就会创建一个HTML解析器。这个解析器是在浏览器级别的代码(通常是C++编写的)基础上运行的,因此执行JavaScript快得多。
我记得我原来在看《DOM启蒙》的时候,书上有说过关于innerHTML的问题,说它很耗性能,尽量避免使用它。当时我也没去求证,并且以为作者的意思是“innerHTML性能很差”,并且还将这个“经验”传授给了我的同学(当然在这次实验过后我告诉了他我之前说的有误)。于是我再次翻开这本书,在书中1.8章节,最后的“注意”中的第3条:
innerHTML调用了一个沉重且高消耗的HTML解析器,而文本节点生成几乎不足为虑;因此省着点用innerHTML和它的小伙伴们。
其实书中说的也没错,是我当时理解错了。innerHTML是很耗能,但是并不代表其执行速度慢比DOM操作慢,况且作者只是将innerHTML和创建文本节点做对比。
二、添加节点实验
1. 计时器
首先我们需要一个计时器:
/**
* 获取当前时间,毫秒为单位
*/
function getTime() {
// 如果浏览器不支持window.performance,就用Date.now()获取当前时间
return window.performance ? window.performance.now() : Date.now();
}
2. 一些需要用到的变量
var div = document.querySelector('div');
var iHtml = ""; // innerHTML这种的字符串
var startTime;
var elNum = 10000; // 每次添加节点的个数
3. 通过innerHTML添加节点
startTime = getTime(); // 开始计时
for (var i = 0; i < elNum; i += 1) {
iHtml += "<p>Hello World</p>";
// 别这么写:
// div.innerHTML += "<p>Hello World</p>";
// 因为这样每次循环都有两个操作:
// 1. 清空之前的innerHTML 2. 赋上新的innerHTML
}
div.innerHTML = iHtml;
console.log(getTime() - startTime); // 输出耗时
3. 通过DOM操作添加节点
startTime = getTime(); // 再次计时
for (var i = 0; i < elNum; i += 1) {
var p = document.createElement('p');
p.appendChild(document.createTextNode('Hello World'));
div.appendChild(p);
}
console.log(getTime() - startTime); // 输出耗时
4. 输出结果
你会发现:
唉????
但你再刷新试试
唉????
你会发现真的很神奇,到底哪个更快啊?
三、删除节点实验
直接在控制台输入
1. innerHTML
startTime = getTime();
div.innerHTML = "";
console.log(getTime() - startTime);
2. DOM操作
startTime = getTime();
for (var i = 0; i < elNum * 2; i += 1) {
div.removeChild(div.firstChild)
}
console.log(getTime() - startTime);
3. 实验结果
innerHTML:
DOM操作:
其实差距也是没多大的
四、添加文本操作
用innerHTML简单添加文本,与DOM操作添加文本节点对比。
注意这里添加的只是单个文本节点,不是多个。
整体代码:
/* =============== 通过innerHTML添加节点 =============== */
console.log('用innerHTML添加' + elNum + '个Hello World文本:');
startTime = getTime(); // 开始计时
for (var i = 0; i < elNum; i += 1) {
iHtml += "Hello World";
}
div.innerHTML = iHtml;
console.log(getTime() - startTime);
/* =============== 通过DOM操作添加节点 =============== */
console.log('用DOM操作添加' + elNum + '个Hello World文本:');
iHtml = '';
startTime = getTime();
for (var i = 0; i < elNum; i += 1) {
iHtml += 'Hello World';
}
div.appendChild(document.createTextNode(iHtml));
console.log(getTime() - startTime);
测试结果:
对于单纯的添加文本,还是DOM操作来的实在
五、个人看法
综上,《DOM启蒙》和《高程3》上说的都没有错,是我的错!
首先,《高程3》上讲的innerHTML在处理添加大量节点的操作上是要比DOM操作要更块,性能更好。
而《DOM启蒙》上说的对于简单的文本操作,还是用DOM操作来完成也确实没错。
网友评论