Как тестировать и оптимизировать JS скрипты

Как тестировать и оптимизировать JS скрипты

Всем привет!

Сегодня мы посмотрим как можно тестировать производительность своего JS кода и, соответственно, оптимизировать его.

Пару месяцев назад я написал статью про Firebug и console, в которой мы рассматривали как пользоваться этой самой консолью. Сегодня мы будем использовать метод console.profile() и увидим как с его помощью можно протестировать и затем улучшить скрипты.

Статья основана на статье Сидхарта «How jQuery beginners can test and improve their code».

Песочница

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

<!DOCTYPE html>
<html lang="ru-RU">
<head>
<title>Тестирование производительности JS скриптов</title>
</head>
<body>
<div id="container">
<div class="block">
<p id="first">Какой-то текст</p>
<ul id="someList">
<li class="item"></li>
<li class="item selected" id="mainItem">Какой-то элемент с текстом</li>
<li class="item"></li>
<li class="item"></li>
</ul>
</div>
</div>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript">
console.profile() ;
// Здесь будем размещать наш код
console.profileEnd();
</script>
</body>
</html>

Сам код будем помещать между console.profile() и console.profileEnd().

Проверка на существование элемента

Часто бывает так, что для всех страниц сайта подгружаются одни и теже скрипты, соответственно, иногда может не быть нужных элементов. Несмотря на то, что jQuery не выполнит код для несуществующих элементов, лучше все-таки делать проверку на существование элементов. Рассмотрим два варианта кода и обратим внимание на время их выполнения. Первый код не делает проверку:

console.profile();
var ele = $("#somethingThatisNotHere");
ele.text("Some text").slideUp(300).addClass("editing");
$("#mainItem");
console.profileEnd();

В результате выполнения этого кода получим вот такую картинку в консоли Фаербага:

Как тестировать и оптимизировать JS скрипты

Второй код проверяет, существуют ли элементы, над которыми нужно выполнить действие:

console.profile() ;
var ele = $("#somethingThatisNotHere");
if ( ele[0] ) {
ele.text("Some text").slideUp(300).addClass("editing");
}
$("#mainItem");
console.profileEnd();

И выдает вот это в консоль:

Как тестировать и оптимизировать JS скрипты

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

Эффективное использование селекторов

Скорее всего вы читали мою статью про оптимизацию CSS. Если нет, то прочитайте. Там я рассказывал о том, как браузеры разбирают селекторы и какие селекторы с какой скорость работают. Если кратко, то быстрее всех работает селектор по id, медленнее всех — универсальные.

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

Для начала попробуем выбрать элементы по классу:

console.profile() ;
$(".selected");
console.profileEnd();

Как тестировать и оптимизировать JS скрипты

Результат 0.308ms. Далее уточним селектор, указав что это должны быть только элементы списка <li>:

console.profile() ;
$("li.selected");
console.profileEnd();

Как тестировать и оптимизировать JS скрипты

Результат 0.291ms — уменьшили на 0.027ms. Теперь еще немного уточним селектор: нужные нам элементы должны находиться внутри контейнера с id="someList":

console.profile() ;
$("#someList .selected");
console.profileEnd();

Как тестировать и оптимизировать JS скрипты

0.283ms — небольшое улучшение. Уточним селектор именем тега:

console.profile() ;
$("#someList li.selected");
console.profileEnd();

Как тестировать и оптимизировать JS скрипты

Получили 0.275ms. Теперь выберем элемент прямо по id ради интереса:

console.profile() ;
$("#mainItem");
console.profileEnd();

Как тестировать и оптимизировать JS скрипты

0.165ms — наш новый рекорд. Теперь думаю ясно как лучше всего писать селекторы.

Избегание излишних операций

Иногда, в коде могут встретиться конструкции типа:

// Какой-то код
$(element).doSomething();

// Потом еще код
$(element).doSomethingElse();

// И еще код
$(element).doMoreofSomethingElse();

Никогда так не делайте. Один элемент запрашивается снова и снова. Это слишком затратно с точки зрения производительности.

Возьмем нашу песочницу и проведем в ней какой-то похожий процесс:

 console.profile() ;
$("#mainItem").hide();
$("#mainItem").val("Привет");
$("#mainItem").html("Привет!");
$("#mainItem").show();
console.profileEnd();

Как тестировать и оптимизировать JS скрипты

Вышеприведенный код так же можно сделать в виде цепочки:

console.profile();
$("#mainItem").hide().val("Привет").html("Привет!").show();
console.profileEnd();

При использовании цепочки, элемент запрашивается один раз и далее методам передается ссылка на него. Это снижает время выполнения.

Так же можно закешировать элемент и производить действия уже над закешированным:

console.profile() ;
var elem = $("#mainItem");
elem.hide();
elem.val("Hello");
elem.html("Oh, hey there!");
elem.show();
console.profileEnd();

Как тестировать и оптимизировать JS скрипты

Как видно из примеров, кеширование и использование цепочек действия снижает время выполнения скриптов.

Умное манипулирование DOM

Как известно, операции с DOM (объектной моделью документа), например получение или вставка элементов, являются очень ресурсоемкими. Давайте посмотрим, как можно ускорить эти операции.

Создадим и добавим в наш документ 50 элементов списка <li>. В первом коде будем добавлять их прямо внутри цикла:

console.profile() ;
var list = $("#someList");
for (var i = 0; i < 50; i ++) { list.append('<li>Item #' + i + '</li>');
}
console.profileEnd();

Как тестировать и оптимизировать JS скрипты

Медленно, не правда ли? Теперь немного изменим алгоритм: в цикле соберем все нужные нам элементы и потом добавим их одним разом в документ:

console.profile() ;
var list = $("#someList");
var items = "";
for (var i = 0; i < 50; i ++){
items += '<li>Item #' + i + '</li>';
}
list.append(items);
console.profileEnd();

Как тестировать и оптимизировать JS скрипты

Как видно, время выполнения существенно уменьшилось.

Заключение

Вы заметили, что время выполнения оптимизированного и неоптимизированного скриптов различается буквально доляи миллисекунд. Это связано с тем, что наш документ очень мал (содержит мало узлов).

Так же заметьте, что в примерах мы просто получали элементы их DOM. Если бы мы начали применять к ним события или что-то еще, разница во времени была бы более существенной.

Расскажите друзьям

Оцените статью:
  • 1
  • 2
  • 3
  • 4
  • 5

Комментарии — 20

Антон
Спасибо, Паш многое не знал.
#
Антон
MyFreeWeb
А в Хроме и Сафари профайлер работает без изменения кода (:
Чистяков Денис
На ряду с селекторами, я бы предложил провести испытания с использованием / без использования контекстов. Они часто удобнее чем боле сложные селекторы, и дают возможность кэширования "отправной точки".
По поводу маленького DOM'а так сделали бы его большим ) взяли бы хотя бы страницу с этой статьей, результаты поиска в яндексе или гугле или какой нить популярный крупный сервис -- было бы нагляднее мне кажется.
А пример с 50-ю LI по моему слегка притянут за уши.
#
Чистяков Денис
Чистяков Денис
Забыл нажать "дополнительная информация" (
#
Чистяков Денис
Вадим
Случайно наткнулся на Ваш блог и мне он очень понравился, подписываюсь однозначно.
Harchenko
Обожаю такие толковые технические посты. Кстати как уже отметили выше, в Google Chrome все проще :)
Константин c69
Радует что дебаггеры и профайлеры уже есть во всех пяти броузерах. И в Хроме, и в Опере (Dragonfly), и в ИЕ, и даже в Сафари.

Ингуш
Harchenko да действительно,хорошо
mamasha
Исправтье «я написал статья».
#
mamasha
алекс экслер
«я написал статья» - умора :))) ROFLMAO - автор ЧУКЧА!!!
#
алекс экслер
максим
Спасибо конечно за статью, но ничего не смог сделать оптимизировал лишь на 6,72% =((((
#
максим
GenRy
Кстати именно сегодня вышла 6 версия браузера Google Chrome... Так что можно протестировать...
#
GenRy
Владимир
Спасибо, за вашу статью нечего об этом не знал а вы помогли, пошел тестировать позже отпишусь как получилось.
artem
спасибо за такую полную статью. узнал все, что хотел.. большего не желал ;)
#
artem
Сео
Не трудный скрипт,с одной стороны))сначала все понятно
krock
для больших CMS актуально. а то кода много.
чёрт его знает, сколько оно там выполняется..
спасибо!
#
krock
Евгений
Отличный скрипт, несложно и полезно
svx
Спасибо за полезный материал, сам активно пользуюсь файрбагом, но про такую фишку не знал, теперь буду активно ее юзать.
#
svx
Likezz
“А пример с 50-ю LI по моему слегка притянут за уши.” - поставь циферку 1000 ... для наглядности ...
#
Likezz

Новый комментарий

как выглядит какой тег
жирный текст <b>жирный текст</b>
курсивный тект <i>курсивный тект</i>
зачеркнутый текст <s>зачеркнутый текст</s>
подчеркнутый текст <u>подчеркнутый текст</u>
ссылка <a href="адрес">ссылка</a>
function foo() { ... }
<pre><code>function foo() { ... } </code></pre>
разрешенные теги или посмотреть как будет выглядеть
как выглядит какой тег
жирный текст <b>жирный текст</b>
курсивный тект <i>курсивный тект</i>
зачеркнутый текст <s>зачеркнутый текст</s>
подчеркнутый текст <u>подчеркнутый текст</u>
ссылка <a href="адрес">ссылка</a>
function foo() { ... }
<pre><code>function foo() { ... } </code></pre>
разрешенные теги или посмотреть как будет выглядеть
counter strike mt2 silkroad pvp metin2 metin2 pvp knight pvp gm olarak başlayan pvpler pvp silkroad pvp serverler counter strike serverler msn show cam show görüntülü sohbet oyunlar suskunlar gazete oku