DOM Traversal

Последняя на сегодняшний день сборка IE9 включает в себя две масштабные взаимосвязанные возможности для работы с DOM – DOM Traversal и Element Traversal. Эти возможности обеспечивают веб-разработчикам простой, гибкий и быстрый путь перемещения по документу, используя единую для всех браузеров разметку. Они имеют форму плоских перечислений, упрощающих DOM-дерево для итерационных списков, и фильтров, которые позволяют настраивать набор узлов при просмотре. Эти функции работают с одной разметкой в различных браузерах – можете протестировать любую часть кода в окне IE9 Platform Preview и любого другого браузера.

Чтобы найти интересующий вас элемент на странице без этих функций, необходимо сделать одно- или многоуровневые просмотры документа с использованием firstChild и nextSibling. Обычно это осуществляется с помощью сложного кода, который работает медленно. С DOM и функциями Element Traversal, появились новые и более эффективные пути решения этой проблемы. Сообщение содержит несколько примеров, показывающих, как это делается.

Я начну с Element Traversal, так как у него самый простой интерфейс, а также знакомые модели для перечисления элементов в DOM. Element Traversal это, по существу, версия DOM Core, оптимизированная для элементов. Вместо того чтобы вызывать функции firstChild и nextSibling, вы вызываете firstElementChild и nextElementSibling. Например:

 

 if (elm.firstElementChild)
{
    elm = elm.firstElementChild;
    
    while (elm.nextElementSibling)
    {
        // Do work...
    }
}

Это быстрее и удобнее, к тому же избавляет вас от проблемы проверки текста и узлов комментариев, когда вы в действительности заинтересованы только в элементах.

DOM Traversal предназначен для более широких случаев. Во-первых, вы создаете NodeIterator или TreeWalker. После этого можно воспользоваться одним из итерационных методов для просмотра дерева:

 

 var iter = document.createNodeIterator(elm, NodeFilter.SHOW_ELEMENT, null, false); // Это также будет работать с createTreeWalker

var node = iter.nextNode();
while (node = iter.nextNode())
{
    node.style.display = "none";
}

Фрагмент кода перебирает в виде простого списка все узлы дерева. Это может оказаться полезным, поскольку в большинстве случаев совершенно безразлично, является ли узел дочерним или соседним, а просто нужно знать, стоит ли он до или после текущей позиции в документе.

Большим преимуществом DOM Traversal является то, что он вводит механизм фильтрации, так что вы работаете только с интересующими узлами. В то время как NodeIterator выполняет только плоские итерации, TreeWalker имеет дополнительные методы, такие как firstChild (), позволяющие оперировать с той частью дерева, с которой хотите.

Семейство констант SHOW_ * дает возможность включать широкий класс узлов, таких как текст или элементы (например, SHOW_ELEMENT в предыдущем примере). Во многих случаях, этого будет достаточно. Но когда требуется точный контроль, можно написать свой собственный фильтр через интерфейс NodeFilter. Интерфейс NodeFilter использует функцию обратного вызова для фильтрации каждого узла, как показано в следующем примере:

 var iter = document.createNodeIterator(elm, NodeFilter.SHOW_ALL, keywordFilter, false);

function keywordFilter(node)
{
   var altStr = node.getAttribute('alt').toLowerCase();
   
   if (altStr.indexOf("flight") != -1 || altStr.indexOf("space") != -1)
      return NodeFilter.FILTER_ACCEPT;
   else
      return NodeFilter.FILTER_REJECT;                
}

Для более наглядного примера, посмотрите демо-версию DOM Traversal – в ней широко используется NodeFilter. Комплекс операций сортировки в списке медиа-элементов столь же прост, как использование функции обратного вызова NodeFilter в примере выше.

В этой статье показано, что у вас есть варианты того, как просмотреть документ. Здесь предлагаются установившиеся правила для случаев, когда необходимо использовать различные интерфейсы:

– Если структура документа очень важна – и вы заинтересованы только в элементах – используйте Element Traversal. Это быстро и не требует написания больших кусков кода.

– Если вы не заботитесь о структуре документа, используйте NodeIterator вместо TreeWalker. Таким образом, само собой разумеется, что вы собираетесь использовать плоский список. Как правило, NodeIterator быстрее, что становится важным при прохождении больших наборов узлов.

– Если константы SHOW_* делают то, что вам нужно для фильтрации, используйте их. Применение констант делает код проще, а также он будет иметь несколько более высокую производительность. Тем не менее, если вам нужна тонкая фильтрация, то не обойтись без обратного вызова NodeFilter.

Я уже открыл для себя эти функции, и они обещают быть большим подспорьем в процессе написания кода, поэтому я очень буду рад, если вы также активно их задействуете. Загрузите последнюю версию Platform Preview, попробуйте API, и дайте нам знать, что вы об этом думаете.

Спасибо!

Джонатан Сейтел (Jonathan Seitel)