Как тестировать и оптимизировать 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>
разрешенные теги или посмотреть как будет выглядеть

metin2 pvp metin2 pvp serverler pvp serverler