jQuery profiling

29 Март 2009

С тех пор как как я написал про то как ускорить селекторы в jQuery меня все беспокоит скорость работы разных частей библиотеки. 21 февраля я проводил тестирование производительности селекторов, а 23 примерно таким же профайлингом занимался John в статье JavaScript Function Call Profiling. Я тогда еще подумал что все что я сделал можно выкинуть, потому что он написал лучше и подробнее.

Но он затронул далеко не все методы, а только основные. Именно этим я сейчас и собираюсь заняться, я собираюсь пройтись по всей документации выписать методы и посмотреть какие методы и сколько времени работают. В общем работа не сложная но нудная. Скрипт замеров уже есть плюс FireUnit мне поможет. Записывать буду имя тестируемого метода, количество вызовов внутри него, соотношение количества внутренних вызовов к количеству выбранных элементов (O), среднее время. Если O меньше 2n, то оно не записывается и считается примерно равным одному n , а n == 40, потому что в примере участвует 40 дивов. Для примера была взята страницы выдачи результатов Google и чуть-чуть подправлена. Да и еще есть такие методы которые работаю только с первым элементом коллекции, в основном получают значение его параметров, для них вноситься отдельная правка.

Пример отрабатывает долго поэтому я вынес его в отдельный файл, смотрите чтоб не подвесил ваш браузер. Хотел сделать еще сравнение по версиям типа 1.3.2 vs 1.2.6 но последний даже не смог полностью отработать - виснет, поэтому предлагаю тем кому действительно интересно сохранить страницу поправить версию и запустить локально, закомментировав половину кода. И там еще какие-то глюки с replaceAll, вроде как из-за него виснет. Но могу сказать заранее, что хоть в более новой версии показатель О выше (больше вызовов функций на каждый элемент), но работает она в среднем быстрее.

И последние перед тем как я дам ссылку на пример его нужно смотреть в FireFox c установленным FireBug и FireUnit. А вот и ссылка на пример.

Для тех кто по каким-то религиозным причинам не хочет ставить себе всё это публикую результат теста проведенного на моей машине.

Attributes/Attr

divs.attr("align"); 6 O(6n) 0.075
divs.attr({align: "center"}); 284 O(7n) 2.381
divs.attr("align", "center"); 284 O(7n) 2.627
divs.attr("align", function () {}); 324 O(8n) 2.089
divs.removeAttr("align"); 204 O(5n) 2.29

Attributes/Class

divs.addClass("test"); 223 O(6n) 1.706
divs.addClass("test"); 244 O(6n) 1.255
divs.hasClass("test"); 11 0.286
divs.removeClass("test"); 304 O(8n) 2.188
divs.removeClass("test"); 247 O(6n) 1.795
divs.toggleClass("test"); 303 O(8n) 2.271
divs.toggleClass("test"); 384 O(10n) 2.739
divs.toggleClass("test", true); 223 O(6n) 1.792
divs.toggleClass("test", true); 244 O(6n) 1.277
divs.toggleClass("test", false); 247 O(6n) 1.81
divs.toggleClass("test", false); 304 O(8n) 2.26

Attributes/HTML

divs.html(); 2 O(2n) 2.221
divs.html("<p>test</p>"); 9907 O(6n+n2) 71.238

Attributes/Text

divs.text(); 6500 O(4n+n2) 35.785
divs.text("test"); 9902 O(6n+n2) 71.749

Attributes/Value

divs.val(); 4 O(4n) 0.04
divs.val("myValue"); 124 O(3n) 1.046
divs.val(["myValue"]); 124 O(3n) 1.082

Traversing/Filtering

divs.eq(0); 9 0.05
divs.hasClass("test"); 11 0.25
divs.filter("div"); 100 O(3n) 0.606
divs.filter(function () {}); 90 O(2n) 0.248
divs.is("div"); 52 0.345
divs.is(".test"); 10 0.228
divs.map(function () {}); 89 O(2n) 0.24
divs.not("div"); 104 O(3n) 0.651
divs.not(".test"); 20 0.329
divs.slice(0, 1); 8 0.048

Traversing/Finding

divs.add("span"); 106 O(3n) 1.369
divs.children("span"); 216 O(5n) 3.238
divs.closest("div"); 690 O(17n) 5.565
divs.closest("span"); 4612 O(3n+n2) 38.784
divs.contents(); 316 O(8n) 3.952
divs.find("span"); 462 O(12n) 5.147
divs.next("span"); 121 O(3n) 1.145
divs.nextAll("span"); 161 O(4n) 1.761
divs.offsetParent("span"); 4 O(4n) 0.311
divs.parent("span"); 100 O(3n) 0.746
divs.parents("span"); 383 O(10n) 3.348
divs.prev("span"); 136 O(3n) 1.445
divs.prevAll("span"); 190 O(5n) 2.478
divs.siblings("span"); 251 O(6n) 3.403

Traversing/Changing

divs.andSelf(); 55 0.425
divs.end(); 2 0.006

Manipulation/Changing Contents

divs.html(); 2 O(2n) 2.196
divs.html("<p>test</p>"); 9907 O(6n+n2) 72.032
divs.text(); 6500 O(4n+n2) 36.241
divs.text("test"); 9902 O(6n+n2) 71.661

Manipulation/Inserting Inside

divs.append("<p>test</p>"); 133 O(3n) 1.675
divs.appendTo("#form"); 176 O(4n) 3.429
divs.appendTo("form"); 191 O(5n) 3.506
divs.appendTo(".form"); 192 O(5n) 3.534
divs.appendTo("<form/>"); 184 O(5n) 3.149
divs.prepend("<p>test</p>"); 133 O(3n) 2.155
divs.prependTo("form"); 191 O(5n) 3.509

Manipulation/Inserting Outside

divs.after("form"); 91 O(2n) 1.903
divs.after("<form/>"); 94 O(2n) 2.078
divs.before("form"); 91 O(2n) 1.457
divs.before("<form/>"); 94 O(2n) 1.611
divs.insertAfter("form"); 190 O(5n) 3.553
divs.insertBefore("form"); 190 O(5n) 3.528

Manipulation/Inserting Around

divs.wrap("<span/>"); 2644 O(2n+n2) 22.655
divs.wrap(document.createElement("span")); 2524 O(2n+n2) 20.983
divs.wrapAll("<span/>"); 181 O(5n) 7.886
divs.wrapAll(document.createElement("span")); 178 O(4n) 7.85
divs.wrapInner("<span/>"); 3245 O(2n+n2) 31.313
divs.wrapInner(document.createElement("span")); 3140 O(2n+n2) 29.689

Manipulation/Replacing

divs.replaceWith("<span/>"); 7636 O(5n+n2) 60.003
divs.replaceAll("span"); 35 1.854

Manipulation/Removing

divs.empty(); 9774 O(6n+n2) 72.261
divs.remove(); 6982 O(4n+n2) 55.583

Manipulation/Copying

divs.clone(); 90 O(2n) 3.304
divs.clone(true); 5309 O(3n+n2) 52.121

CSS/CSS

divs.css("color"); 4 O(4n) 0.136
divs.css("color", "red"); 205 O(5n) 2.119
divs.css({color: "red", border: "1px solid red"}); 365 O(9n) 4.112

CSS/Positioning

divs.offset(); 2 O(2n) 0.337
divs.position(); 14 0.51
divs.scrollTop(); 2 O(2n) 0.112
divs.scrollTop(10); 44 0.475
divs.scrollLeft(); 2 O(2n) 0.112
divs.scrollLeft(10); 44 0.468

CSS/Height and Width

divs.height(); 12 O(12n) 24.01
divs.height(10); 206 O(5n) 2.271
divs.width(); 12 O(12n) 10.789
divs.width(10); 206 O(5n) 2.189
divs.innerHeight(); 10 O(10n) 10.782
divs.innerWidth(); 10 O(10n) 10.533
divs.outerHeight(); 5 O(5n) 10.195
divs.outerHeight(true); 10 O(10n) 10.483
divs.outerWidth(); 5 O(5n) 10.216
divs.outerWidth(true); 10 O(10n) 10.342

Effects/Basics

divs.show(); 162 O(4n) 8.007
divs.show(); 253 O(6n) 2.991
divs.hide(); 162 O(4n) 4.168
divs.hide(); 42 0.393
divs.toggle(); 845 O(21n) 23.782
divs.toggle(true); 325 O(8n) 10.757
divs.toggle(false); 325 O(8n) 5.31

Effects/Sliding

divs.slideUp(); 1328 O(33n) 8.703
divs.slideUp(); 3679 O(2n+n2) 101.01
divs.slideDown(); 2280 O(n2) 62.462
divs.slideDown(); 2200 O(n2) 61.412
divs.slideToggle(); 4927 O(3n+n2) 156.157

Effects/Fading

divs.fadeIn(); 1448 O(36n) 22.658
divs.fadeIn(); 1368 O(34n) 21.313
divs.fadeOut(); 1328 O(33n) 9.04
divs.fadeOut(); 1288 O(32n) 15.798
divs.fadeTo(0, 0.5); 1968 O(n2) 17.539
  1. 29 Март 2009 в 23:48 | #1
    Хм, очень интересно, но в "Attributes/Class" зачем по два раза повторил? >>> divs.closest("div"); 690 O(17n) 5.565 divs.closest("span"); 4612 O(3n+n2) 38.784 <<< Это глюк? Меня удивляет "690" и "4612", почему настолько различается?
  2. 29 Март 2009 в 23:58 | #2
    потому что когда ищется closest проверяется сам элемент. вот в первом случаи он проверился и вернул сам себя, а во втором пошел реально искать ближайший span.
Комментирование отключено.