Самый эффективный способ перебора всех элементов DOM?
К сожалению, мне нужно перебирать все элементы 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
}
Я предполагаю, что собственный вариант выполняется быстрее. Удивление, если есть другие варианты, которые я не рассматривал. Может быть, рекурсивный вариант, который повторяется над дочерними узлами параллельно.
Ответы
Ответ 1
Ванильный способ Javascript, который вы опубликовали, является самым быстрым. Это будет быстрее, чем решение jQuery, которое вы разместили (см. Мой комментарий к вопросу). Если вы не удаляете или ничего не добавляете в DOM в своем цикле, и порядок обхода не имеет значения, вы также можете немного ускорить его, итерации в обратном направлении:
var items = startElem.getElementsByTagName("*");
for (var i = items.length; i--;) {
//do stuff
}
Изменить: проверьте этот показатель, чтобы узнать, сколько времени вы можете сохранить, используя собственный код: http://jsben.ch/#/Ro9H6
Ответ 2
ОБНОВЛЕНИЕ:
Не используйте $('body *')
для перебора элементов. При использовании метода JQuery гораздо проще использовать $('*')
(подробнее см. Комментарии).
Plain ol 'JavaScript намного быстрее, относительно говоря.
Используя test fiddle, я получаю около 30 мс для обработки 13000 элементов с помощью JQuery и 8 мс для обработки 23000 элементов с использованием JavaScript (оба тестируются на Chrome):
JQuery: 433 elements/ms
JavaScript: 2875 elements/ms
Difference: 664% in favor of plain ol' JavaScript
Примечание. Если на вашей странице нет невероятно большого количества элементов, это не будет иметь большого значения. Кроме того, вы, вероятно, должны время логики в вашем цикле, поскольку это может быть ограничивающим фактором во всем этом.
Update:
Здесь - это обновленные результаты при рассмотрении гораздо большего количества элементов (около 6500 за цикл), я получаю около 648000 элементов в 1500 мс с помощью JQuery и 658000 элементов в 170 мс с JavaScript. (оба протестированы в Chrome):
JQuery: 432 elements/ms
JavaScript: 3870 elements/ms
Difference: 895% in favor of plain ol' JavaScript
Похоже, JavaScript ускорился, а JQuery остался примерно таким же.
Ответ 3
Это не очень хорошая идея, но это должно работать:
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;
}
Под редакцией!
Ответ 4
Самый быстрый способ выглядит document.all
(обратите внимание, что это свойство, а не метод).
Я изменил скрипту ответа Бриги, чтобы записать их вместо jQuery, и он последовательно быстрее (чем document.getElementsByTagName('*')
).
Скрипка.
Ответ 5
Это решение проблемы, как описано в комментариях (хотя и не в актуальном вопросе). Я думаю, что было бы гораздо быстрее использовать elementFromPoint
для проверки области, в которую вы хотите поместить элемент фиксированной позиции, и беспокоиться только об элементах в этой области. Пример:
http://jsfiddle.net/pQgwE/4/
В принципе, просто установите минимальный возможный размер элемента, который вы ищете, и отсканируйте всю область, которую хочет занять ваш новый элемент фиксированной позиции. Создайте список уникальных элементов, найденных там, и беспокоитесь только о проверке стиля этих элементов.
Обратите внимание, что этот метод предполагает, что элемент, который вы ищете, имеет самый высокий индекс z (что представляется разумным предположением для фиксированной позиции). Если это недостаточно, то это можно скорректировать, чтобы скрыть (или присвоить минимальный z-индекс) каждому элементу после его обнаружения и снова проверить точку, пока не будет найдено ничего (если это необходимо), а затем восстановить их потом. Это должно происходить так быстро, чтобы быть незаметным.
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 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});