Когда использовать NodeIterator - PullRequest
6 голосов
/ 29 октября 2011

Бенчмарк сравнивает QSA & .forEach с NodeIterator

toArray(document.querySelectorAll("div > a.klass")).forEach(function (node) {
  // do something with node
});

var filter = {
    acceptNode: function (node) {
        var condition = node.parentNode.tagName === "DIV" &&
            node.classList.contains("klass") &&
            node.tagName === "A";

        return condition ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT
    }  
}
// FIREFOX Y U SUCK
var iter = document.createNodeIterator(document, NodeFilter.SHOW_ELEMENT, filter, false);
var node;
while (node = iter.nextNode()) {
    // do thing with node    
}

Теперь либо NodeIterator отстой, либо я делаю это неправильно.

Вопрос: Когда мне следует использовать NodeIterator?

Если вы не знаете, DOM4 указывает, что такое NodeIterator .

1 Ответ

10 голосов
/ 30 октября 2011

Это медленно по разным причинам. Наиболее очевидным является тот факт, что никто не использует его так просто, гораздо меньше времени было потрачено на его оптимизацию. Другая проблема заключается в массовом повторном входе, каждый узел должен вызывать JS и запускать функцию фильтра.

Если вы посмотрите на ревизию 3 эталонного теста , вы обнаружите, что я добавил повторную реализацию того, что делает итератор, используя getElementsByTagName("*"), а затем запустил идентичный фильтр для этого. Как показывают результаты, это значительно быстрее. Идет JS -> C ++ -> JS медленно.

Полная фильтрация узлов в JS (случай getElementsByTagName) или C ++ (случай querySelectorAll) выполняется намного быстрее, чем повторное пересечение границы.

Обратите внимание, что сопоставление селекторов, используемое querySelectorAll, сравнительно разумно: оно выполняет сопоставление справа налево и основано на предварительно вычисленных кэшах (большинство браузеров перебирают кэшированный список всех элементов с классом "класс", проверьте, является ли он элементом a, а затем проверьте, является ли родительский элемент div), и, следовательно, они даже не будут перебирать весь документ.

Учитывая, что, когда использовать NodeIterator? По крайней мере, в JavaScript. В таких языках, как Java (несомненно, это основная причина, по которой существует интерфейс с именем NodeIterator), он, скорее всего, будет таким же быстрым, как и все остальное, так как тогда ваш фильтр будет на том же языке, что и фильтр. Кроме того, единственный раз, когда это имеет смысл, это в языках, где использование памяти для создания объекта Node намного больше, чем внутреннее представление Node.

...