querySelectorAll vs NodeIterator vs TreeWalker - 最快的纯 JS 平面 DOM 迭代器
querySelectorAll vs NodeIterator vs TreeWalker - fastest pure JS flat DOM iterator
我想将 DOM 树展平成 Array
。
结果应包括根作为第一个条目。
普通 JS 解决方案是首选。
实现该目标的最快方法是什么?
HTML结构示例:
<div class="tested-root">
<span></span>
<span></span>
<div>
<span></span>
<span></span>
</div>
<div>
<span></span>
<span></span>
</div>
</div>
预计输出为:
[div.tested-root, span, span, div, span, span, div, span, span]
或类似的(这个是 DFS,但对于这个问题来说并不重要)。
下面三种方法中哪个最快:
querySelectorAll
NodeIterator
TreeWalker
我最近又来试了几次。
下面是从最慢到最快的结果,同时指定慢的比最快的如何。
Chrome based results. Safari shows roughly the same numbers. Firefox has issues with that perf app and was not verified.
方法 1(不移位)慢 81%
const list = Array.from(root.querySelectorAll('*'));
list.unshift(root);
方法 2(传播)~77% 慢
const list = [root, ...root.querySelectorAll('*')];
方法 3(NodeIterator)~慢 32%
const list = [];
const ni = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT);
let next;
while (next = ni.nextNode()) {
list.push(next);
}
方法 4(树行者)最快
const list = [root];
const tw = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
let next;
while (next = tw.nextNode()) {
list.push(next);
}
奖励(空根检查)慢 1%(空根快 98%)
const list = [root];
if (root.childElementCount) {
const tw = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
let next;
while (next = tw.nextNode()) {
list.push(next);
}
}
观察与结论
- 数组操作,if/when 考虑,表明传播 (
...
) 运算符方式比 unshift
方法 更快
- 主要性能提升来自使用本机迭代器,
TreeWalker
是目前最快的
- 几乎总是实施特殊的speed-up奖励是合理的,对于嵌套结构,影响可以忽略不计,但对于空树它运行两倍更快
可以找到基准测试 here。
我想将 DOM 树展平成 Array
。
结果应包括根作为第一个条目。
普通 JS 解决方案是首选。
实现该目标的最快方法是什么?
HTML结构示例:
<div class="tested-root">
<span></span>
<span></span>
<div>
<span></span>
<span></span>
</div>
<div>
<span></span>
<span></span>
</div>
</div>
预计输出为:
[div.tested-root, span, span, div, span, span, div, span, span]
或类似的(这个是 DFS,但对于这个问题来说并不重要)。
下面三种方法中哪个最快:
querySelectorAll
NodeIterator
TreeWalker
我最近又来试了几次。 下面是从最慢到最快的结果,同时指定慢的比最快的如何。
Chrome based results. Safari shows roughly the same numbers. Firefox has issues with that perf app and was not verified.
方法 1(不移位)慢 81%
const list = Array.from(root.querySelectorAll('*'));
list.unshift(root);
方法 2(传播)~77% 慢
const list = [root, ...root.querySelectorAll('*')];
方法 3(NodeIterator)~慢 32%
const list = [];
const ni = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT);
let next;
while (next = ni.nextNode()) {
list.push(next);
}
方法 4(树行者)最快
const list = [root];
const tw = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
let next;
while (next = tw.nextNode()) {
list.push(next);
}
奖励(空根检查)慢 1%(空根快 98%)
const list = [root];
if (root.childElementCount) {
const tw = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
let next;
while (next = tw.nextNode()) {
list.push(next);
}
}
观察与结论
- 数组操作,if/when 考虑,表明传播 (
...
) 运算符方式比unshift
方法 更快
- 主要性能提升来自使用本机迭代器,
TreeWalker
是目前最快的 - 几乎总是实施特殊的speed-up奖励是合理的,对于嵌套结构,影响可以忽略不计,但对于空树它运行两倍更快
可以找到基准测试 here。