querySelector和getElementBy方法的比较

今天发现了一个新的API用来获取页面中的节点元素querySelectorquerySelectorAll,他们的作用和getElementByXXX系列是一样的。下面看一下这个新方法的性能如何。

程序执行时间测试方法

先来科普一下如何看某段程序的运行时间。其实方法很简单:

1
2
3
4
5
var start = +new Date();
someLongProcess();
var stop = +new Date();
console.log(stop - start); // 函数执行时间

像上面这样我们就可以获取到函数的运行时间

构造测试环境

为了使测试效果更明显,我们先构造一个巨大的DOM树:

1
2
3
4
5
<!--index.html-->
<body>
<div id="root"></div>
<script src="./index.js" type="text/javascript"></script>
</body>

1
2
3
4
5
6
7
8
// index.js
var root = document.getElementById('root');
var html = '';
for(var i = 0; i < 50000; i++) {
html += '<span class="test-span-tag"><a class="inner-class-name"></a></span>';
}
root.innerHTML = html;

这样我们就得到了一个内部有5W个span元素的DOM树结构

下面我们将比较querySelectorAll()方法和getElementsByTagName()方法的性能

性能测试

1
2
3
4
5
6
7
8
9
10
11
12
13
// getElementsByTagName 方法
var ta1 = +new Date();
var domWay = document.getElementsByTagName('span');
var ta2 = +new Date();
domWay[0].innerHTML = '0';
var ta3 = +new Date();
// querySelectorAll 方法
var tb1 = +new Date();
var apiWay = document.querySelectorAll('span');
var tb2 = +new Date();
apiWay[0].innerHTML = '1';
var tb3 = +new Date();

可以看到我们在执行要比较的两个函数之前和之后分别调用了new Date()来获取当前时刻,他们的差值就是两个函数获取节点所需的信息;后面我们又对获取到的节点进行了赋值操作。

最后输出时间间隔

1
2
3
4
5
6
var record = document.createElement('div');
record.innerHTML = '<p>document.getElementById("root").getElementsByTagName("span"): ' + (ta2 - ta1) + 'ms</p>\
<p>document.getElementById("root").getElementsByTagName("span") 并改变一个节点的值: ' + (ta3 - ta1) + 'ms</p>\
<p>document.querySelectorAll("#root span"): ' + (tb2 - tb1) + 'ms</p>\
<p>document.querySelectorAll("#root span") 并改变一个节点的值: ' + (tb3 - tb1) + 'ms</p>';
root.appendChild(record);

源代码

每次结果都有些差异,我截取了其中一个结果

图片

我们可以看到,使用getElementsByTagName方法,在获取节点的过程中,性能是相当好的,获取5W个节点的集合,时间基本不会超过1ms,相对来说querySelectorAll方法的性能就稍差一些;这么说来querySelectorAll的出现就没有意义了吗?答案是否定的。我们可以观察到,如果对获取到的节点集合进行简单的操作,getElementsByTagName消耗的时间会很长,而querySelectorAll几乎不消耗时间,这是为什么呢?

原理

当我们在使用getElementsByClassName方法的时候,我们得到的节点集合是实时的,也就是说,每次对集合进行操作之前,都会重新遍历一遍节点以获取DOM树中最新的状态,可以理解为获得了节点集合的引用;而querySelectorAll方法正相反,其获得的是DOM树中当前时刻节点集合的快照,是静态的值。

结论

于是我们可以得出结论,如果只要单纯的获取DOM树中节点的集合,而不需要改变节点元素的时候,getElementsByClassName方法的速度要快很多;如果要对集合中的节点元素进行批量操作的时候,可以选择使用querySelectorAll方法来提高性能

转载请注明出处 http://cthblog.cn/2017/03/07/querySelector-vs-dom-method/

坚持原创技术分享,您的支持将鼓励我继续创作!