首页 > 解决方案 > querySelectorAll vs NodeIterator vs TreeWalker - 最快的纯 JS 平面 DOM 迭代器

问题描述

我想将 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,但就这个问题而言并不重要)。

从以下三种方法中哪个是最快的:

标签: javascripthtmlperformancedomtraversal

解决方案


我最近才来尝试其他一些。下面的结果从最慢到最快,同时指定如何比最快慢。

基于 Chrome 的结果。Safari 显示的数字大致相同。Firefox 与该性能应用程序存在问题,并且未经验证。

方法 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 (TreeWalker)最快

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);
    }
}

观察和结论

  • 数组运算,如果/当考虑时,表明 spread ( ...) 运算符方式比unshift方法快
  • 主要的性能提升来自使用本机迭代器,TreeWalker是迄今为止最快的
  • 实现这种特殊的加速奖励几乎总是合理的,对于嵌套结构,影响可以忽略不计,但对于一棵空树,它的运行速度要快两倍

基准测试可以在这里找到。


推荐阅读