迭代所有DOM元素的最有效方法?

kev*_*ler 63 javascript optimization performance jquery dom

不幸的是,我需要迭代页面的所有DOM元素,我想知道最有效的技术是什么.我可以自己对这些进行基准测试,如果我有时间可能,但我希望有人已经经历过这个或有一些我没有考虑的选择.

目前我正在使用jQuery并执行此操作:

$('body *').each(function(){                                                                                                                            
      var $this = $(this);                                                                                                                                
      //do stuff                                                                                                                                         
});
Run Code Online (Sandbox Code Playgroud)

虽然它有效,但它似乎会导致客户端出现一些延迟.它也可以用更具体的jQuery上下文进行调整,比如$('body', '*') 我发现本机javascript通常比jQuery更快,我发现了这一点.

var items = document.getElementsByTagName("*");
    for (var i = 0; i < items.length; i++) {
        //do stuff
    }
Run Code Online (Sandbox Code Playgroud)

我假设本机选项更快.想知道是否有其他选择我没有考虑过.也许是一个递归选项,可以并行迭代子节点.

Pau*_*aul 46

您发布的Vanilla Javascript方式最快.它会比您发布的jQuery解决方案更快(请参阅我对该问题的评论).如果你没有在你的循环中删除或添加任何东西,并且遍历的顺序无关紧要,你也可以通过反向迭代来加速它:

var items = startElem.getElementsByTagName("*");
for (var i = items.length; i--;) {
    //do stuff
}
Run Code Online (Sandbox Code Playgroud)

编辑:检查此基准测试以查看使用本机代码可以节省多少时间:http://jsben.ch/#/Ro9H6

  • @BrianJ`i - `是循环的条件部分.这就像是说'i--!= 0`,但是因为'0`是'falsy`你可以把这部分关掉 (14认同)

Bri*_*y37 16

更新:

不要$('body *')用于迭代元素.$('*')如果你使用JQuery方法,它将更快地使用(请参阅注释以获取详细信息).


简单来说,相对而言,JavaScript的速度要快得多.

使用测试小提琴,我使用JQuery处理13000个元素大约需要30ms,使用JavaScript处理23000个元素需要8ms(两者都在Chrome上测试):

JQuery:      433  elements/ms
JavaScript:  2875 elements/ms

Difference:  664% in favor of plain ol' JavaScript
Run Code Online (Sandbox Code Playgroud)

注意: 除非您的页面上有大量的元素,否则这不会产生太大的影响.此外,您可能应该在循环中计算逻辑,因为这可能是所有这些中的限制因素.

更新:

以下是考虑更多元素(每个循环大约6500个)时的更新结果,使用JQuery在1500ms内获得大约648000个元素,使用JavaScript在170ms中获得658000个元素.(均在Chrome上测试过):

JQuery:      432  elements/ms
JavaScript:  3870 elements/ms

Difference:  895% in favor of plain ol' JavaScript
Run Code Online (Sandbox Code Playgroud)

看起来JavaScript加快了,而JQuery保持不变.

  • 你正在jQuery循环中做一些你不在另一个循环中的东西:将每个元素转换为jQuery对象`var $ this = $(this);`.使两个迭代器完全相同,我想你会发现这种差异在很大程度上消失了. (3认同)
  • 不,这不对."this"是循环中已经存在的元素...就像本机方法返回的元素一样.为什么你必须在一种情况下将它转换为jQuery对象,而不是另一种情况?他们的开始是一样的. (2认同)
  • 这是一个基于你的更公平的测试(两者使用相同的选择器,以及相同的迭代方法):http://jsfiddle.net/Pv8zm/4/ (2认同)
  • @kevzettler:我认为该方法也会迭代文本节点,因此它会增加处理的节点数量.见[this test](http://jsfiddle.net/briguy37/Pv8zm/9/). (2认同)

Pet*_*bev 14

一般来说这不是一个好主意,但这应该有效:

function walkDOM(main) {
    var arr = [];
    var loop = function(main) {
        do {
            arr.push(main);
            if(main.hasChildNodes())
                loop(main.firstChild);
        }
        while (main = main.nextSibling);
    }
    loop(main);
    return arr;
}
walkDOM(document.body);
Run Code Online (Sandbox Code Playgroud)

不包括文本节点:

function walkDOM(main) {
    var arr = [];
    var loop = function(main) {
        do {
            if(main.nodeType == 1)
                arr.push(main);
            if(main.hasChildNodes())
                loop(main.firstChild);
        }
        while (main = main.nextSibling);
    }
    loop(main);
    return arr;
}
Run Code Online (Sandbox Code Playgroud)

编辑!

  • 我采用了这种方法并将其与下面的一些基准集成在一起.它看起来要快得多.我错过了什么吗?http://jsfiddle.net/Pv8zm/7/ (2认同)

Cam*_*tin 6

最快的方式似乎是document.all(注意它是属性,而不是方法).

我已经修改了Briguy的答案,而不是使用jQuery来记录这些,而且它的速度始终快于(比document.getElementsByTagName('*')).

小提琴.