最有效的方法遍历所有的DOM元素?

不幸的是,我需要遍历页面的所有DOM元素,我想知道最有效的技术是什么。 我大概可以基准这些自己,如果我有时间,但我希望有人已经经历了这个或有一些select,我没有考虑。

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

$('body *').each(function(){ var $this = $(this); //do stuff }); 

虽然它起作用,但似乎会给客户带来一些滞后。 它也可以使用像$('body', '*')这样更具体的jQuery上下文来调整。我发现原生javascript通常比jQuery更快,而且我发现它。

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

我假设本地选项更快。 想知道是否有其他的select,我没有考虑。 也许是并行迭代子节点的recursion选项。

您发布的Vanilla Javascript方式是最快的。 这将比您发布的jQuery解决scheme更快(请参阅我对该问题的评论)。 如果你没有在你的循环中删除或添加任何东西到DOM中,遍历的顺序并不重要,你也可以通过反向迭代来加快它的速度:

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

编辑 :检查这个基准,看看您可以节省多less时间通过使用本机代码: http : //jsben.ch/#/Ro9H6

更新:

不要使用$('body *')遍历元素。 如果您使用JQuery方法,请使用$('*')更快(详见注释)。


Plain ol'JavaScript相对来说要快得多。

使用testing小提琴 ,我用JQuery获得了大约30ms的时间来处理13000个元素,使用JavaScript处理23000个元素的时间是8ms(都在Chrome上testing过):

 JQuery: 433 elements/ms JavaScript: 2875 elements/ms Difference: 664% in favor of plain ol' JavaScript 

注意:除非页面上的元素数量非常多,否则这不会有太大区别。 另外,你可能应该在循环中计算逻辑,因为这可能是所有这些限制因素。

更新:

当考虑更多的元素(每个循环约6500个)时,更新的结果是这样的,在JQuery中,我获得了约1500,000个元素中的648000个元素,以及使用JavaScript的170ms中的658000个元素。 (都在Chrome上testing过):

 JQuery: 432 elements/ms JavaScript: 3870 elements/ms Difference: 895% in favor of plain ol' JavaScript 

看起来像JavaScript加快而JQuery保持不变。

这通常不是一个好主意,但是这应该起作用:

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

不包括文本节点:

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

编辑!

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

我已经修改了Briguy的答案logging这些而不是jQuery,它一直更快(比document.getElementsByTagName('*') )。

小提琴

这是评论中描述的问题的解决scheme(虽然不是真正的问题)。 我认为使用elementFromPoint来testing要放置固定位置元素的区域会更快,而且只担心该区域中的元素。 这里是一个例子:

http://jsfiddle.net/pQgwE/4/

基本上,只要设置一个你正在寻找的元素的最小可能的大小,并扫描你的新的固定位置元素要占据的整个区域。 build立一个在那里find的独特元素的列表,只是担心检查这些元素的风格。

请注意,这种技术假设你正在寻找的元素具有最高的z-索引(这对于固定位置似乎是合理的假设)。 如果这不够好,那么可以调整它以隐藏(或分配一个最小z-索引)到每个元素被发现后,再次testing点,直到没有更多的发现(确定),然后恢复他们之后。 这应该发生得如此之快以至于不可察觉。

HTML:

 <div style="position:fixed; left: 10px; top: 10px; background-color: #000000; color: #FF0000;">I Am Fixed</div> <div id="floater">OccupyJSFiddle!<br>for two lines</div> 

JS:

 var w = $(window).width(), h=$(window).height(), minWidth=10, minHeight=10, x,y; var newFloat = $('#floater'), maxHeight = newFloat.height(), el, uniqueEls=[], i; for (x=0;x<w;x+=minWidth) { for (y=0;y<h&& y<maxHeight;y+=minHeight) { el = document.elementFromPoint(x,y); if (el && $.inArray(el,uniqueEls)<0) { uniqueEls.push(el); } } } // just for the fiddle so you can see the position of the elements // before anything's done // alert("click OK to move the floater into position."); for (i=0;i<uniqueEls.length;i++) { el = $(uniqueEls[i]); if (el.css("position")==="fixed") { el.css("top",maxHeight+1); } } newFloat.css({'position': 'fixed', 'top': 0, 'left': 0});