Подтвердить что ты не робот

Самый эффективный способ перебора всех элементов 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
    }

Я предполагаю, что собственный вариант выполняется быстрее. Удивление, если есть другие варианты, которые я не рассматривал. Может быть, рекурсивный вариант, который повторяется над дочерними узлами параллельно.

4b9b3361

Ответ 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});