В первой статье цикла я уже рассматривал скорость работы движка, ответственного за создание и отображение HTML-страницы на экране. Однако, сейчас речь пойдет о несколько другом аспекте, нежели движок CSS-селекторов. Данная серия тестов была посвящена скорости создания отдельного HTML-документа.
Методика
Если в первых двух исследованиях ставилась под вопрос скорость распознавания браузером CSS-правил и их применение, то сейчас интересовал другой вопрос, а именно: как быстро браузер создает DOM-дерево в зависимости от наличия в нем элементов с id или class?
Для этого было подготовлено 3 набора HTML-файлов. Первый содержал 10000 элементов, у которых часть имеет id (количество именованных элементов варьировалось от 50 до 10000). Во втором HTML-файлы были, практически, идентичными, только вместо id имели атрибут class. В третьем наборе в DOM-дереве были только элементы с id (т.е. варьировалось само число элементов). Соответственно, все измерения проводились в скрытом iframe, чтобы избежать отрисовки загружаемой страницы на экране.
Для замера времени создания страницы применялась та же, хорошо зарекомендовавшая себя, техника, что и в предыдущих тестах: бралась метка времени до набора элементов и после этого набора, затем из последней вычиталась первая. Итоговые результаты являются средневзвешенными по всем браузерам.
Влияние на getElementById
Дополнительно для тех HTML-файлов, которые содержали идентификаторы, запускалось вычисление getElementById('id1') 10000 раз (чтобы проверить, насколько количество элементов или идентификаторов влияет на эту процедуру). Результаты получились весьма интересные, хотя и очень предсказуемые. Наверное, в следующих исследования этот аспект работы браузеров будет исследован несколько подробнее.
Тесты
Сами тесты можно погонять тут или скачать на указанной странице все одним архивом (вместе с моими результатами).
Все 3 тестовых набора (каждый содержал по 6 файлов, в них было 50, 100, 500, 1000, 5000 и 10000 исследуемых элементов) прогонялся по 10 раз для 5 браузеров (Firefox2, IE6, IE7, Opera 9.5 (да-да, не стоит у меня 9.27) и Safari 3). В результате, статистическими методами погрешность сводилась ко вполне допустимому значению: 2–3%.
Сразу хочу оговориться о небольшом всплеске для самого первого документа у всех браузеров: скорее всего, при загрузке документа в iframe браузер (это было характерно абсолютно для всех) выделяет определенное количество памяти для нового HTML-документа в этом iframe, которое затем каким-либо образом повторно использует для новых документов. В результате для документа с 50 идентификаторами на 10000 элементов результаты оказались несколько неверными.
Наверное, в будущем этот аспект стоит учесть и загружать пустой документ в самом начале или, что лучше, загружать документ с максимальным количеством объектов, чтобы выделение памяти не влияло на дальнейшие измерения. Однако, на качественные выводы данное отклонение никак не повлияло.
Результаты
Наверное, проще всего будет представить результаты в виде графиков, что я, в принципе и сделаю. Пару слов о легенде: на ней собрано 5 случаев. ID (create) отражает время создания HTML-документа с 10000 элементов (div), из которых только у 50...10000 были идентификаторы. class (create) соответствует времени создания такого же документа, но с class вместо id. ID (clean) характеризует время создания документа, в котором все элементы имели идентификаторы (но элементов всего было 50...10000). Два графика с 10000 get показывают время на получения элемента с конкретным идентификатором 10000 раз в первом и третьем документе, соответственно.
Сами графики:
|ID%20(10000%20get)|class%20(create)|ID%20(clean)|ID%20clean%20(10000%20get))
Рисунок 1. Скорость создания документа и выборки элемента для Firefox 2
|ID%20(10000%20get)|class%20(create)|ID%20(clean)|ID%20clean%20(10000%20get))
Рисунок 2. Скорость создания документа и выборки элемента для IE 6
|ID%20(10000%20get)|class%20(create)|ID%20(clean)|ID%20clean%20(10000%20get))
Рисунок 3. Скорость создания документа и выборки элемента для IE 7
|ID%20(10000%20get)|class%20(create)|ID%20(clean)|ID%20clean%20(10000%20get))
Рисунок 4. Скорость создания документа и выборки элемента для Opera 9.5
|ID%20(10000%20get)|class%20(create)|ID%20(clean)|ID%20clean%20(10000%20get))
Рисунок 5. Скорость создания документа и выборки элемента для Safari 3
Для Internet Explorer тяжело что-то понять, ибо время на вычисление элемента по идентификатору по порядку ненамного меньше времени создания документа, в итоге, оно «забивает» все результаты. Ниже приведены разделенные графики по средневзвешенному значению (естественно, основную роль играет Internet Explorer).
|class%20(create)|ID%20(clean))
Рисунок 6. Скорость создания документа, средневзвешенно по всем браузерам
|ID%20clean%20(10000%20get))
Рисунок 7. Скорость выборки элемента, средневзвешенно по всем браузерам
Выводы
По графику средневзвешенных значений хорошо видно, что, при прочих равных условиях, создание документа с class обходится меньшей кровью, чем с id (в общем случае, от 2 до 10% выигрыша). Если принять во внимание, что element.class-селекторы отрабатывают быстрее, чем #id на те же 10%, то общий выигрыш при использовании в документе классов перед идентификаторами составит порядка 15%. В абсолютном значении эти цифры не так велики: для Centrino Duo 1.7 получается цифра примерно в 0,0085мс на 1 идентификатор (в среднем, 3 CSS-правила и 1 употребление).
Для документа со 100 элементами выигрыш может составить почти 1мс, для документа с 1000 — 8,5мс! Замечу, что средняя страница в интернете имеет 500–1000 элементов (проверить, сколько элементов на странице, можно просто запустив javascript:alert(document.getElementsByTagName('*').length) в адресной строке браузера на какой-либо открытой странице), поэтому это уже то, за что можно побороться.
Однако (что и требовалось доказать, в общем), значительную нагрузку составляет именно создание DOM-дерева в документе (можно посмотреть, как экспоненциально растет время для Opera, Firefox и Safari) и самого документа (постоянное время в 60мс для IE, которое превосходит все остальные накладные расходы при создании среднего документа). В целом, эти операции уходит от 70% всего времени (т.е. наибольшая экономия достигается за счет минимизации размера дерева и количество HTML-страниц, загружаемых, например, во фрейме, в этой области планируется провести дополнительные исследования).
На скорость вычисления одного элемента по идентификатору, как ни странно, наибольшее влияние оказывает опять-таки DOM-Дерево, чем количество таких элементов. Даже при 1000 элементов с id более половины временных издержек можно урезать, если просто сократить общее число элементов (особенно хорошо это заметно для IE).
В целом же, основных советов пока два: уменьшайте DOM-дерево и используйте id только в случае действительной необходимости.