Статьи

Автор: Николай Мациевский aka sunnybear
Опубликована: 5 мая 2008

Скорость выборки CSS-селекторов в JavaScript-библиотеках

Наряду со сравнительными тестами времени загрузки различных JavaScript-библиотек было интересно посмотреть, насколько оптимизированы в них наиболее популярные действия, а именно: выбор элементов по CSS-селекторам. Ведь даже в простейшем JavaScript-коде на основе таких библиотек используется, порой, несколько десятков таких операций, не говоря уже о сложных интерфейсах и полноценных веб-приложениях.

Приведу характерный пример кода для jQuery, который использует движок CSS-селекторов:

$(function(){
    $("a.clip").click(function(){
        $("#clip"+$(this).attr("rel")).slideToggle(500);
        if($(this).html() == "+") {
	    $(this).html("–");
	} else {
	    $(this).html("+");
	}
        return false;
    });
})

В этом примере на все ссылки с class равным clip навешивается обработчик onclick, который либо показывает блок, id которого соответствует значению атрибута rel у ссылки (в начале id идет clip, затем порядковый номер), либо скрывает его. HTML-код при этом внутри ссылки меняется с «+» на «–» или обратно, соответственно. Вся эта логика выполняется по загрузке странице через встроенный метод $(function(){}).

Казалось бы, ничего сверхъестественного, обычное, рядовое действие. Однако, в нем используется 2 обращения к движку CSS-селекторов, и это, обычно, минимум для такого рода операций (я не учитываю вызовы $(this), которые являются обращениями к созданному объекту, а не самому движку). Вопрос, которым стоило бы задаться: насколько быстро можно выбирать элементы по заданным CSS-строкам?

Тестирование производительности

Я думаю, в Интернете уже существует несколько таких тестов. В частности, Павел Корнилов aka lusever создал замечательное тестовое окружение, в котором можно выбрать огромное количество текущих JavaScript-библиотек с целью сравнить их производительность на предмет CSS-селекторов (его пост на Хабре).

Однако, после моего замечания по поводу нерелевантности выбора селекторов и раздумий, а что же будет релевантной выборкой? (кстати, практически одновременно этим же вопросом задался John Resig и решил его несколько по-другому, наверное, больше в требуемом ключе, но об этом чуть позже) было решено несколько пересмотреть тест и внести поправки на основе используемости селекторов. Как же мы это сделали?

Статистические данные

На основе статистических данных с webo.in было проанализировано около 10 тысяч CSS-файлов, в общей сложности было отобрано около полумиллиона CSS-селекторов, которые затем были классифицированы. Для классификации использовались результаты тестов по производительности CSS-селекторов в браузере (в частности, было решено не рассматривать более второго уровня вложения, ибо быстродействие все равно будет вычисляться рекурсивно).

Итоговая таблица получилась примерно следующего вида:

Таблица 1. Частота использования CSS-селекторов
СелекторЧастота использования
tag.class21,63%
.class tag17,63%
.class .class12,31%
tag11,56%
#id9,41%
#id .class8,92%
#id tag8,5%
#id #id3%
tag#id2,12%
tag tag1,18%
.class1,12%
* something1,05%
.class #id0,84%
tag .class0,32%
something>something0,27%
*0,11%
#id *0,03%

Результаты

По ее результатам было сделано взвешенная оценка производительности различных JavaScript-библиотек.

Далее, этот набор прогонялся по 5 браузерам (FF 2, IE6, IE7, Opera 9.5, Safari 3), результаты и средневзвешенное значение ускорение. Небольшой комментарий: Opera 9.5 падала в двух различных местах в этой матрице библиотек-селекторов, поэтому в тестах не участвовала. В таблице приведено ускорение работы библиотеки относительно самой медленной из аналогов.

Таблица 2. Ускорение работы движка CSS-селекторов в различных браузерах
Firefox 2IE 6IE 7Opera 9Safari 3Среднее
YUI 2.5.10%30%45%0%0%24,45%
Dojo Toolkit 1.0.254%56%43%38%63%49,18%
MooTools 1.2 beta 244%1%5%53%62%17,22%
DOMAssistant 2.782%82%81%82%100%81,93%
base2 1.0b288%70%78%64%100%73,33%
ext 2.161%66%70%47%86%63,04%
jQuery 1.2.354%26%40%21%47%31,84%
Prototype 1.6.0.275%0%0%71%84%22,58%

Выводы

Самой быстрой оказалась библиотека DOMAssistant, обогнав даже base2 (от Dean Edwards). Что более удивительно, jQuery показала весьма посредственные результаты (хотя John Resig довольно большое количество решений почерпнул именно у Dean Edwards), но обогнала-таки Prototype.

Как я уже упоминал, релевантность выборки селекторов волновала не меня одного. John Resig выложил свои результаты, однако, он использовал другой, наверное, более верный, подход: он исследовал около тысячи JavaScript-файлов, которые используют jQuery и составил рейтинг используемости различных селекторов. К несчастью, при правильном подходе это довольно трудоемкое решение (сложно представляю, как его можно корректно автоматизировать), которое требует различных рейтингов для разных библиотек. Хорошая новость заключается в том, что его результаты не настолько кардинально отличаются от моих (в частности, в выборке присутствуют одни и те же селекторы, просто с разными весами).

Отдельное спасибо хочется сказать, естественно,  lusever и  vithar. И всем, кто осилил статью до конца :)

Читать дальше

Все комментарии (habrahabr.ru)