不幸的是我需要遍历页面的所有DOM元素,我想知道最有效的技术是什么。我可以自己对这些进行基准测试,如果我有时间可能,但我希望有人已经经历过这个或有一些我没有考虑的选择。
目前我正在使用jQuery并执行此操作:
$('body *').each(function(){
var $this = $(this);
//do stuff
});
虽然它有效,但它似乎会导致客户端出现一些延迟。它也可以使用更具体的jQuery上下文进行调整,例如$('body', '*')
在我看来,本机javascript通常比jQuery更快,我发现了这一点。
var items = document.getElementsByTagName("*");
for (var i = 0; i < items.length; i++) {
//do stuff
}
我假设原生选项更快。想知道是否有其他选择我没有考虑过。也许是一个递归选项,可以并行迭代子节点。
答案 0 :(得分:45)
您发布的Vanilla Javascript方式最快。它会比您发布的jQuery解决方案更快(请参阅我对该问题的评论)。如果你没有在你的循环中删除或添加任何东西,并且遍历的顺序无关紧要,你也可以通过反向迭代来加速它:
var items = startElem.getElementsByTagName("*");
for (var i = items.length; i--;) {
//do stuff
}
修改:检查此基准测试,了解使用本机代码可以节省多少时间:http://jsben.ch/#/Ro9H6
答案 1 :(得分:16)
更新:
不要使用$('body *')
迭代元素。如果你选择JQuery方法,那么使用$('*')
要快得多(详见评论)。
使用test fiddle,使用JQuery处理13000个元素大约需要30ms,使用JavaScript处理23000个元素需要8ms(两者都在Chrome上测试):
JQuery: 433 elements/ms
JavaScript: 2875 elements/ms
Difference: 664% in favor of plain ol' JavaScript
注意:除非您的网页上有大量的元素,否则这不会产生太大的影响。此外,您可能应该在循环中计算逻辑,因为这可能是所有这些中的限制因素。
<强>更新强>
Here是考虑更多元素(每个循环大约6500)的更新结果,我使用JQuery在1500ms内获得大约648000个元素,在使用JavaScript的170ms中获得658000个元素。 (均在Chrome上测试过):
JQuery: 432 elements/ms
JavaScript: 3870 elements/ms
Difference: 895% in favor of plain ol' JavaScript
看起来JavaScript加快了,而JQuery保持不变。
答案 2 :(得分: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);
不包括textnodes:
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;
}
编辑!
答案 3 :(得分:6)
最快的方式似乎是document.all
(注意它是属性,而不是方法)。
我已经修改了Briguy的回答来解决这些问题,而不是jQuery,并且它一直更快(比document.getElementsByTagName('*')
)。
答案 4 :(得分:3)
这是评论中描述的问题的解决方案(尽管不是实际问题)。我认为使用elementFromPoint
来测试你想要放置固定位置元素的区域要快得多,并且只担心该区域中的元素。这里有一个例子:
基本上,只需设置您正在寻找的元素的最小可能大小,并扫描新固定位置元素想要占用的整个区域。构建一个在那里找到的独特元素的列表,并且只担心检查这些元素的样式。
请注意,此技术假设您要查找的元素具有最高的z-index(这似乎是固定位置的合理假设)。如果这还不够好,那么可以调整它以便在每个元素被发现后隐藏(或指定最小的z-index)并再次测试该点,直到找不到更多(确定),然后恢复他们之后。这应该发生得如此之快以至于难以察觉。
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});
答案 5 :(得分:1)
最有效:
const allDom = document.all || document.querySelectorAll("*");
const len = allDom.length;
for(let i=0; i<len; i++){
let a = allDom[i];
}