querySelectorAll vs NodeIterator vs TreeWalker - 最快的纯 JS 平面 DOM 迭代器

Gul*_*rYA 6 html javascript performance dom traversal

我想将 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>
Run Code Online (Sandbox Code Playgroud)

预期的输出是: [div.tested-root, span, span, div, span, span, div, span, span]或类似的(这是 DFS,但对于这个问题来说并不重要)。

从以下三种方法中,哪种方法最快:

  • querySelectorAll
  • NodeIterator
  • TreeWalker

Gul*_*rYA 12

我最近才来尝试另外几个。下面的结果从最慢到最快,同时指定较慢的一项如何比最快的一项。

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

方法 1(未换档)约慢 81%

const list = Array.from(root.querySelectorAll('*'));
list.unshift(root);
Run Code Online (Sandbox Code Playgroud)

方法 2(传播)约慢 77%

const list = [root, ...root.querySelectorAll('*')];
Run Code Online (Sandbox Code Playgroud)

方法 3 (NodeIterator)慢约 32%

const list = Array.from(root.querySelectorAll('*'));
list.unshift(root);
Run Code Online (Sandbox Code Playgroud)

方法 4 (TreeWalker)最快

const list = [root, ...root.querySelectorAll('*')];
Run Code Online (Sandbox Code Playgroud)

奖励(空根检查)约慢 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

观察和结论

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

可以在此处找到基准测试。

  • 这种“比较”是没有意义的。这取决于文档的结构、浏览器、浏览器的版本、浏览器的内部结构、进行测量的程序/客户端、程序运行的硬件,... (2认同)
  • 然后将所有这些变量添加到您的“答案”中...... (2认同)