Pull to refresh

25 советов по улучшению вашего кода jQuery

jQuery *
Translation
Original author: Jon Hobbs-Smith
Это перевод статьи, написанной Jon Hobbs-Smith. Я счел ее довольно интересной и решил выложить в своем блоге, а также поделиться им с хабрапользователями, также как и я заинтересованными в библиотеке jQuery. Перед тем как начать хочу отметить, что написана она (как и переведена) далеко не экспертом в jQuery, поэтому если вы найдете в ней ошибку, пожалуйста, сообщите. Итак, начнем.

1. Загружайте библиотеку с Google Code

На Google Code хранится несколько популярных Javascript библиотек, в том числе и jQuery, при этом есть несколько способов их подключения к вашему сайту. Надо сказать, что подгружаются они довольно быстро, к тому же если пользователь до этого посещал сайт, где библиотека подгружается таким же образом как и у вас с Google, то файл вообще загрузиться с кеша.

Подгрузить библиотеку можно через специально предусмотренный для этого API:




Либо напрямую:



Подробнее о способах подключения вы можете прочитать здесь.

2. Используйте шпаргалки

И не только для jQuery. В сети сейчас можно найти довольно большое количество удобных шпаргалок по многим языкам и библиотекам формата А4, так что ее можно к примеру распечатать и повесить на стенку рядом с компьютером.

Вот ссылки на пару таких:
http://www.gscottolson.com/weblog/2008/01/11/jquery-cheat-sheet/
http://colorcharge.com/jquery/

Кроме того, мы обсуждали шпаргалки в одном из ранних постов.

3. Совмещайте и сжимайте ваши скрипты

Наверное, это один из главных советов по Javascript. Особенно это относиться к проектам, использующим большое количество плагинов. Большинство браузеров не может загружать файлы скриптов одновременно, а последовательная загрузка значительно увеличивает общее время загрузки всей страницы. Поэтому рекомендуется собирать все файлы в один большой скрипт.

Не забывайте сжимать ваш код. Большинство плагинов уже минимизированы, в противном случае рекомендуется сделать это, тем более это займет у вас всего несколько секунд. Например, можно воспользоваться Packer от Dean Edwards.

4. Используйте Firebug

Если вы его еще не установили, вы просто должны это сделать. Помимо таких замечательных вещей, как просмотр http трафика и обнаружения проблем в CSS эта надстройка ведет отличный лог команд, который может помочь вам в обнаружении ошибок в ваших скриптах.

Здесь вы найдете подробное описание всех его возможностей.

Очень полезна «console.info», с помощью которой вы можете выводить сообщения и значения переменной на экран без использования алертов, а также «console.time», которая позволяет вам засекать время выполнения определенных участков кода. Все они довольно просты в использовании.

console.time('create list');

for (i = 0; i < 1000; i++) {
var myList = $('.myList');
myList.append('This is list item ' + i);
}

console.timeEnd('create list');


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

5. Кэшируйте ваши селекторы.

Селекторы в jQuery потрясающие. С их помощью очень просто выбирать элементы на странице, но если вы используете их очень интенсивно в своем скрипте, это может существенно замедлить работу страницы.

Если вы все время обращаетесь к одному и тому же селектору, то можете просто внести его в память и затем использовать сколько угодно, не боясь навредить быстродействию. Давайте посмотрим следующий код:

for (i = 0; i < 1000; i++) {
var myList = $('.myList');
myList.append('This is list item ' + i);
}


Выполнение этого простого кода заняло 1066 миллисекунд на моем компьютере в FF3 (представьте, как долго он бы выполнялся в IE6!). Теперь выполним аналогичный код, но используем селектор только один раз:

var myList = $('.myList');

for (i = 0; i < 1000; i++) {
myList.append('This is list item ' + i);
}


И что вы думаете? Всего 224 миллисекунды, более чем в 4 раза быстрее, а ведь мы передвинули всего одну линию кода :-)

6. Сведите манипуляцию с DOM к минимуму.

Мы можем еще ускорит код из предыдущего совета, сведя к минимуму работу с DOM. Операции для работы с DOM, такие как .append(), .prepend(), .after() и .wrap() очень дорогое удовольствие и частое их использование может также увеличить время выполнения вашего кода.

Все что потребуется в нашем случае — это использовать конкатенацию строк для построения списка, а затем использовать единожды метод .html() и наш код станет заметно быстрее. Давайте посмотрим пример.

var myList = $('#myList');

for (i=0; i<1000; i++){
myList.append('This is list item ' + i);
}


На моем компьютере он выпольнялся 216 миллисекунд, всего 1/5 секунды, но если мы сначала построим список в виде строки, а затем используем HTML метод для вставки следующим образом:

var myList = $('.myList');
var myListItems = '';

for (i = 0; i < 1000; i++) {
myListItems += 'This is list item ' + i + '';
}

myList.html(myListItems);


То такой скрипт будет выполняться уже 185 миллисекунд, на 31 миллисекунду быстрее. Какая-никакая, но все же экономия времени, а в случае с более сложным кодом эффективность будет более ощутима.

7. Оборачивайте все в один элемент прежде чем работать с DOM

Я не могу объяснить, почему это так работает, но наверняка эксперты в jQuery дадут на это ответ.

Дело в следующем. В нашей последнем примере мы вставили 1000 элементов списка в один элемент неупорядоченного списка, используя метод .html(). Если бы мы сначала обернули их в тег UL перед вставкой, а затем уже сформированный список вставляли в другой тег, например DIV, то это было бы намного эффективнее и быстрее, чем вставлять 1000 элементов. Давайте посмотрим пример, чтобы все стало ясно…

var myList = $('.myList');
var myListItems = '<ul>';

for (i = 0; i < 1000; i++) {
myListItems += '<li>This is list item ' + i + '</li>';
}

myListItems += '</ul>';
myList.html(myListItems);


Такой код выполняется всего 19 миллисекунд, почти в 50 раз быстрее нашего самого первого примера.

8. Используйте идентификаторы вместо классов

В jQuery селекторы по классу такие же удобные, как и селекторы по идентификатору, что сделало их не менее популярными. Но все же лучше выбирать элементы по ID, так как jQuery использует для этого родной для каждого браузера метод getElementByID, а не какие то свои методы. Давайте посмотрим пример.

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

// Создаем наш список
var myList = $('.myList');
var myListItems = '<ul>';

for (i = 0; i < 1000; i++) {
myListItems += '<li class="listItem' + i + '">This is a list item</li>';
}

myListItems += '</ul>';
myList.html(myListItems);

// Выбираем по разу каждый элемент списка
for (i = 0; i < 1000; i++) {
var selectedItem = $('.listItem' + i);
}


Как я и ожидал, это задание заметно подгрузило мой браузер. По итогу время выполнения кода составило 5066 миллисекунд (более 5 секунд). Затем я изменил код и задал каждому элементу списка свой идентификатор взамен класса, а затем обратился к каждому элементу по его ID.

// Создаем наш список
var myList = $('.myList');
var myListItems = '<ul>';

for (i = 0; i < 1000; i++) {
myListItems += '<li id="listItem' + i + '">This is a list item</li>';
}

myListItems += '</ul>';
myList.html(myListItems);

// Выбираем по разу каждый элемент списка
for (i = 0; i < 1000; i++) {
var selectedItem = $('#listItem' + i);
}


Этот код выполнялся всего 61 миллисекунду. Почти в 100 раз быстрее.

9. Задавайте контекст в селекторах

По умолчанию, когда вы используете любой селектор, например $('.myDiv'), будет проанализирована вся структура DOM в его поисках, что на больших страницах может быть довольно накладно.

В таких случаях не надо забывать, что при построении селектора может быть задан второй параметр:

jQuery(выражение, контекст)

Устанавливая параметр контекст, вы указываете в каком именно элементе искать необходимый элемент, тем самым jQuery не придется просматривать всю структуру DOM.

Для демонстрации этого возьмем первый блок кода из предыдущего примера. Он создает несортированный список с 1000 элементов, у каждого из которых свой класс. Далее пробегаясь по всему списку он обращается к каждому классу. Эта операция заняла порядка 5 секунд чтобы перебрать таким образом каждый элемент.

var selectedItem = $('#listItem' + i);

Затем был добавлен параметр контекста, который выполнял селектор только внутри ненумерованного списка:

var selectedItem = $('#listItem' + i, $('.myList'));

Выполнение этого кода заняло 3818 миллисекунд, что на 25% быстрее. А ведь мы опять же внесли всего небольшое изменение в код.

10. Используйте цепочки

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

$('myDiv').removeClass('off').addClass('on');

Не стоит забывать, что код прекрасно работает с переносами строки (ведь jQuery = JavaScript), а это позволяет сделать ваш код более опрятным и читабельным, например, как в следующем примере.

$('#mypanel')
.find('TABLE .firstCol')
.removeClass('.firstCol')
.css('background' : 'red')
.append('Эта ячейка теперь красная!');


Стоить отметь, что привычка использовать цепочку методов помогает вам сократить код в использовании селекторов.

Но это еще не все. А что если вы хотите применить ряд функций к элементу, но одна из них меняет внешний вид элемента, например, как в следующем коде…

$('#myTable').find('.firstColumn').css('background','red');

Мы выбрали таблицу, нашли в ней ячейки класса firstColumn и покрасили их в красный цвет.

А давайте теперь еще закрасим все ячейки класса lastColumn в синий? Потому как мы использовали метод find(), мы отфильтровали из набора все элементы, которые не имеют класса firstColumn, таким образом, нам нужно использовать этот селектор снова, чтобы выбрать нужные элементы таблицы и не сможем продолжить цепочку методов. К счастью в jQuery имеется метод end(), который позволяет вернуться к предыдущему набору элементов, как в следующем примере.

$('#myTable')
.find('.firstColumn')
.css('background','red')
.end()
.find('.lastColumn')
.css('background','blue');


Кроме того, написать свою функцию, которую можно использовать в цепочке это намного проще, чем вы думаете. Для этого достаточно в по итогу выполнения всех действий с элементом вернуть его.

$.fn.makeRed = function() {
return $(this).css('background', 'red');
}

$('#myTable').find('.firstColumn').makeRed().append('привет');


Не правда ли, все достаточно просто?

11. О методе animate()

Когда я только начал использовать jQuery мне очень нравились уже определенные методы анимации, такие как slideDown() и fadeIn(), с помощью которых просто и быстро можно было сделать потрясающие эффекты. В основе каждой из этих функций лежит метод animate(), который очень функциональный и так же очень легко используется.

slideDown: function(speed,callback){
return this.animate({height: "show"}, speed, callback);
},

fadeIn: function(speed, callback){
return this.animate({opacity: "show"}, speed, callback);
}


Метод animate() просто изменяет различные свойства CSS от одного значения к другому. Таким образом, вы можете изменять высоту, ширину, прозрачность, цвет фона, различные отступы и все остальное что только пожелаете.

Например, вот так можно легко анимировать ваше меню, изменяя высоту элемента до 100 пикселей при наведении мышки.

$('#myList li').mouseover(function() {
$(this).animate({"height": 100}, "slow");
});


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

$('#myBox').mouseover(function() {
$(this).animate({ "width": 200 }, "slow");
$(this).animate({"height": 200}, "slow");
});


Если же вы хотите, чтобы анимация выполнялась параллельно, просто поместите оба стиля в объект параметров вызова метода, например, как в следующем примере.

$('#myBox').mouseover(function() {
$(this).animate({ "width": 200, "height": 200 }, "slow");
});


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

12. Делегирование событий

С помощью jQuery очень просто привязывать события к элементам DOM, это замечательно, но привязка большого количества событий нерационально. Делегирование событий позволяет с помощью привязки меньшего количества событий достичь желаемого результата во многих ситуациях. Посмотрим пример.

$('#myTable TD').click(function(){
$(this).css('background', 'red');
});


Простая функция по клику окрашивает ячейки таблицы в красный цвет. А теперь представьте, если у нас таблица из 10 колонок и 50 строк, получается мы привязываем событие к 500 элементам. А что если бы мы могли привязать событие к таблице, а затем по клику на таблице определяли, какую именно ячейку окрасить в красный цвет?

Это как раз и называется делегированием событий. Давайте посмотрим, как оно работает.

$('#myTable').click(function(e) {
var clicked = $(e.target);
clicked.css('background', 'red');
});


'e' содержит информацию о событии, включая объект, по которому был произведен щелчок мышкой. Все что от нас требуется, это определить, по какой именно ячейке кликнул пользователь.

Кроме этого, делегирование элементов имеет еще один плюс. Обычно, когда вы привязываете событие к каким-либо элементам, то оно привязывается именно к этим элементам и никаким более. Если вы в процессе работы страницы добавили новые элементы в DOM, которые также соответствуют селектору, то к ним обработчик применятся уже не будет. В случае использования делегирования вы можете добавлять сколько угодно элементов в DOM после привязки события и с ними не будет никаких проблем.

13. Используйте классы для хранения состояний

Это самый простой путь для хранения информации о блоке html кода. jQuery хороша для манипулирования элементами с помощью классов, таким образом, если вам необходимо хранить информацию о состоянии какого-либо элемента, почему бы не воспользоваться специальным классом для этой цели?

В следующем примере мы создадим выпадающее меню. По клику на слое класса button подменю (класс panel) будет выпадать через slideDown() если оно не показано или прятаться через slideUp() если оно наоборот открыто. Итак, начнем с HTML.

<div class="menuItem expanded">
<div class="button">
Нажми меня
</div>
<div class="panel">
<ul>
<li>Элемент меню 1</li>
<li> Элемент меню 2</li>
<li> Элемент меню 3</li>
</ul>
</div>
</div>


Очень просто! Теперь добавим специальный класс, который будет хранить состояние подменю. В итоге нам будет необходимо лишь написать обработчик клика по диву класса button, который будет прятать либо показывать наше подменю с помощью slideUp() и slideDown() соответственно.

$('.button').click(function() {

var menuItem = $(this).parent();
var panel = menuItem.find('.panel');

if (menuItem.hasClass("expanded")) {
menuItem.removeClass('expanded').addClass('collapsed');
panel.slideUp();
}
else if (menuItem.hasClass("collapsed")) {
menuItem.removeClass('collapsed').addClass('expanded');
panel.slideDown();
}
});


Это очень простой пример, но вы можете добавлять специальные классы для хранения любой необходимой информации о каком-либо фрагменте HTML кода.

Как правило, такой подход используется в простых случаях. В более сложных лучше обратиться к содержанию следующего совета.

14. Используйте также встроенный метод data() для хранения данных

По каким-то причинам функция, о которой пойдет речь ниже не очень хорошо документирована, но тем не менее в jQuery есть встроенный метод data(), который может быть использован для хранения информации вида ключ-значение для любого элемента DOM. Посмотрим пример его использования.

$('#myDiv').data('currentState', 'off');

Мы можем доработать пример из предыдущего совета. Будем использовать тот же HTML код, но для хранения информации воспользуемся методом data().

$('.button').click(function() {

var menuItem = $(this).parent();
var panel = menuItem.find('.panel');

if (menuItem.data('collapsed')) {
menuItem.data('collapsed', false);
panel.slideDown();
}
else {
menuItem.data('collapsed', true);
panel.slideUp();
}
});


Думаю, вы согласитесь, что такой будет лучше. Для более подробной информации о методах data() и removeData() вы можете посетить раздел документации jQuery.

15. Пишите свои селекторы

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

Конечно, можно изначально назначить им классы и затем обращаться к этим элементам через него. Но это не так сложно создать свой собственный селектор.

Давайте посмотрим пример.

$.extend($.expr[':'], {
over100pixels: function(a) {
return $(a).height() > 100;
}
});

$('.box:over100pixels').click(function() {
alert('The element you clicked is over 100 pixels high');
});


Первый блок кода создает селектор, который выбирает все элементы, которые по высоте больше 100 пикселей. Второй блок используется для привязки обработчика клика по таким элементам. Можно развивать эту тему дальше, но я думаю, вы уже заметили насколько это мощный инструмент и с легкостью обнаружите большое количество других самописных селекторов на гугле.

16. Упрощайте HTML и модифицируйте его при загрузке

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

<div class="fieldOuter">
<div class="inner">
<div class="field">Это поле номер 1</div>
</div>
<div class="errorBar">
<div class="icon"><img src="icon.png" alt="icon" /></div>
<div class="message"><span>Это сообщение об ошибке</span></div>
</div>
</div>
<div class="fieldOuter">
<div class="inner">
<div class="field"> Это поле номер 2</div>
</div>
<div class="errorBar">
<div class="icon"><img src="icon.png" alt="icon" /></div>
<div class="message"><span> Это сообщение об ошибке </span></div>
</div>
</div>


Это пример разметки формы, немного модифицированный для наглядности. Я уверен, вы согласитесь, что код выглядит не очень красиво, и при большом размере формы вы получите не менее неприятную страницу. Согласитесь, следующий код выглядит намного лучше.

<div class="field"> Это поле номер 1</div>
<div class="field"> Это поле номер 2</div>
<div class="field"> Это поле номер 3</div>
<div class="field"> Это поле номер 4</div>
<div class="field"> Это поле номер 5</div>


Все что теперь от вас требуется это с помощью jQuery вернуть повторяющиеся фрагменты кода на место.

$(document).ready(function() {
$('.field').before('<div class="fieldOuter"><div class="inner">');
$('.field').after('</div><div class="errorBar"><div class="icon">
<img src="icon.png" alt="icon" /></div><div class="message">
<span> Это сообщение об ошибке </span></div></div></div>');
});


Не всегда советуется поступать таким образом, потому как при загрузке страницы может быть заметно подгрузка фрагментов кода, но в некоторых случаях, когда у вас много повторяющегося HTML кода, этот совет поможет уменьшить вес вашей страницы, а также преимущества в SEO при уменьшении повторяющихся фрагментов очевидны.

17. Подгрузка контента ради скорости и SEO

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

Сделать это можно как в следующем примере…

$('#forms').load('content/headerForms.html', function() {
// Здесь подгружаем весь необходимый нам код
});


Думаю, здесь все и так понятно, особо останавливаться не будем.

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

18. Используйте функции jQuery

jQuery служит не только для создания крутых эффектов анимации. Разработчики встроили в библиотеку несколько действительно полезных методов, которые могут восполнить некоторые недостатки функционала JavaScript в целом.

http://docs.jquery.com/Utilities

В частности, некоторые браузеры неполноценно поддерживают функции для работы с массивами (IE7 например даже не поддерживает метод indexOf()). jQuery имеет методы для итерации, фильтрации, клонирования, слияния и удаления дубликатов из массивов.

Другая распространенная проблема это трудность с получением выбранного элемента в выпадающем списке. В обычном JavaScript вы не сможете получить элемент SELECT через getElementByID, получить его дочерние элементы как массив и пройтись по ним, определив, какой из них выбран а какой нет. jQuery с легкостью решает эту проблему…

$('#selectList').val();

Поэтому лучше потерять немного времени и порыться в документации jQuery на основном сайте, почитав о других малоизвестных, но очень полезных функциях.

19. Используйте noconflict при работе совместно с другими библиотеками

Большинство javascript библиотек используют символ $ в своих целях, что может вызвать ошибки при использовании более чем одного фреймворка на одной странице. К счастью эта проблема просто решается с помощью метода .noconflict(), как в следующем примере.

var $j = jQuery.noConflict();
$j('#myDiv').hide();


20. Как узнать, что рисунок загрузился

Это еще одна из тех проблем, которая недостаточно документирована, как того стоит, но тем не менее очень часто всплывает при построении фотогалерей, каруселей и т.д., и на самом деле решается довольно просто.

Все что потребуется это воспользоваться методом .load() для элемента IMG и колбэк функцией по завершению загрузки в нем. В следующем примере изменяется атрибут src в теге рисунка для загрузки нового изображения и привязывается простая функция загрузки.

$('#myImage').attr('src', 'image.jpg').load(function() {
alert('Изображение загружено');
});


Как вы поняли, алерт появится по окончанию загрузки рисунка.

21. Всегда используйте последнюю версию

jQuery постоянно улучшается, а ее создатель Джон Резиг (John Resig) все время ищет пути для повышения производительности библиотеки. В связи с этим рекомендуется постоянно следить за обновлениями фреймворка (стабильными версиями) и обновлять вашу рабочую версию.

22. Как проверить, что элемент существует

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

if ($('#myDiv).length) {
// Ваш код
}


Просто и очевидно.

23. Добавляйте класс JS к тегу HTML

Этот трюк описывается в книге Карла Сведберга (Karl Swedberg).

Первым делом при загрузке jQuery добавьте класс JS к вашему тегу HTML.

$('HTML').addClass('JS');

Поскольку это произойдет только если поддержка JavaScript включена на стороне пользователя, вы можете по этой же причине добавить специальный CSS стиль…

.JS #myDiv{display:none;}

Таким образом вы можете скрыть содержимое страницы, если поддержка JavaScript включена и затем используя jQuery показать его, если это необходимо (это относится например к выпадающим панелям, которые отображаются по клику на них). Пользователь без JavaScript (а также поисковые роботы) просто увидит все содержимое.

24. Возвращайте «false» чтобы избежать действия по умолчанию

Это вполне очевидно, но для кого-то может быть и незнакомо. Если вы имеете привычку делать вот так…

Нажми меня!

…а затем привязываете какой-нибудь обработчик событий, как например этот…

$('popup').click(function(){
// какой-нибудь код
});


…то все будет замечательно до той поры, пока вы не будете работать с этим на длинной странице, на которой вы увидите, что при клике на ссылке с # вы попадете на верх вашей странички.

Все что требуется в этом случае, чтобы избежать действия по умолчанию это добавить «return false;» в ваш обработчик события, например вот так…

$('popup').click(function(){
// какой-нибудь код
return false;
});


25. Укороченная запись события ready

Маленький совет по укороченной записи $(document).ready, который поможет сэкономить пару символов, но все же.

Вместо этого…

$(document).ready(function (){
// ваш код
});


Можно написать…

$(function (){
// ваш код
});


Спасибо за внимание. Этот и другие посты по jQuery вы также можете найти в моем блоге, посвященном данной библиотеке. К тому же, всегда буду рад видеть вас среди своих фолловеров на Твиттере.
Tags:
Hubs:
Total votes 97: ↑86 and ↓11 +75
Views 28K
Comments Comments 78