Наряду со сравнительными тестами времени загрузки различных 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-селекторов в браузере (в частности, было решено не рассматривать более второго уровня вложения, ибо быстродействие все равно будет вычисляться рекурсивно).
Итоговая таблица получилась примерно следующего вида:
Селектор | Частота использования |
---|---|
tag.class | 21,63% |
.class tag | 17,63% |
.class .class | 12,31% |
tag | 11,56% |
#id | 9,41% |
#id .class | 8,92% |
#id tag | 8,5% |
#id #id | 3% |
tag#id | 2,12% |
tag tag | 1,18% |
.class | 1,12% |
* something | 1,05% |
.class #id | 0,84% |
tag .class | 0,32% |
something>something | 0,27% |
* | 0,11% |
#id * | 0,03% |
По ее результатам было сделано взвешенная оценка производительности различных JavaScript-библиотек.
Далее, этот набор прогонялся по 5 браузерам (FF 2, IE6, IE7, Opera 9.5, Safari 3), результаты и средневзвешенное значение ускорение. Небольшой комментарий: Opera 9.5 падала в двух различных местах в этой матрице библиотек-селекторов, поэтому в тестах не участвовала. В таблице приведено ускорение работы библиотеки относительно самой медленной из аналогов.
Firefox 2 | IE 6 | IE 7 | Opera 9 | Safari 3 | Среднее | |
---|---|---|---|---|---|---|
YUI 2.5.1 | 0% | 30% | 45% | 0% | 0% | 24,45% |
Dojo Toolkit 1.0.2 | 54% | 56% | 43% | 38% | 63% | 49,18% |
MooTools 1.2 beta 2 | 44% | 1% | 5% | 53% | 62% | 17,22% |
DOMAssistant 2.7 | 82% | 82% | 81% | 82% | 100% | 81,93% |
base2 1.0b2 | 88% | 70% | 78% | 64% | 100% | 73,33% |
ext 2.1 | 61% | 66% | 70% | 47% | 86% | 63,04% |
jQuery 1.2.3 | 54% | 26% | 40% | 21% | 47% | 31,84% |
Prototype 1.6.0.2 | 75% | 0% | 0% | 71% | 84% | 22,58% |
Самой быстрой оказалась библиотека DOMAssistant, обогнав даже base2 (от Dean Edwards). Что более удивительно, jQuery показала весьма посредственные результаты (хотя John Resig довольно большое количество решений почерпнул именно у Dean Edwards), но обогнала-таки Prototype.
Как я уже упоминал, релевантность выборки селекторов волновала не меня одного. John Resig выложил свои результаты, однако, он использовал другой, наверное, более верный, подход: он исследовал около тысячи JavaScript-файлов, которые используют jQuery и составил рейтинг используемости различных селекторов. К несчастью, при правильном подходе это довольно трудоемкое решение (сложно представляю, как его можно корректно автоматизировать), которое требует различных рейтингов для разных библиотек. Хорошая новость заключается в том, что его результаты не настолько кардинально отличаются от моих (в частности, в выборке присутствуют одни и те же селекторы, просто с разными весами).
Отдельное спасибо хочется сказать, естественно, lusever и vithar. И всем, кто осилил статью до конца :)