Pull to refresh

Правила эффективного использования jQuery

Reading time5 min
Views43K
Здесь приведен ряд очень простых правил, следуя которым, ваше сотрудничество с jQuery не будет омрачено скрежетом напрягшегося браузера. Конечно, не так часто случается, что скорость работы javascript’а оказывается критичной, однако такое все же может произойти, и произойти в самый неподходящий момент. Поэтому, лучше держать эти правила в голове и не пренебрегать ими.


1. Эффективный поиск элементов


Быстрее всего происходит поиск элементов по идентификатору: $('#someId'), вторым по быстродействию, является поиск по имени тега: $('tagName'). Высокая скорость их выполнения связана с тем, что для их реализации используются внутренние функции javascript: getElementById() и getElementsByTagName(). В связи с этим, появляются несколько правил.

(Для большей наглядности, укажу текст страницы, к которому будут применен JS-код из примеров)
<div id="content">
  <form method="post" action="/">
    <h2>Выбери цвет</h2>
    <ul id="color_light">
      <li><input type="radio" class="on" name="light" value="red" /> Красный</li>
      <li><input type="radio" class="off" name="light" value="yellow" /> Желтый</li>
      <li><input type="radio" class="off" name="light" value="green" /> Зеленый</li>
    </ul>
    <input class="button" id="color_button" type="submit" value="Go" />
  </form>
</div>

* This source code was highlighted with Source Code Highlighter.


1. Если вы ищете один элемент, используйте поиск по идентификатору:
$('#color_button') – будет выполнен максимально быстро
$('#content .button') – будет медленнее
$('.button:first') – еще медленнее

2. Если вы ищете группу элементов, указывайте ближайшего общего родственника, обладающего идентификатором:
$('#content input') будет эффективнее, чем просто $('input').

3. Если вы ищете элементы по классу, указывайте имя тега:
$('input.button') выполнит поиск быстрее, чем $('.button'). В первом случае, jQuery вначале найдет все элементы input, и уже среди них будет искать элементы с классом button. А во втором случае, для этого будет произведен перебор всех элементов страницы.

Из всего сказанного, можно вывести два основных правила:
1) Для поиска одного элемента, используйте поиск по id: $('#someId')
2) При поиске группы элементов, старайтесь придерживаться следующей формулы: $('#someId tagName.someClass')

И еще, не пытайтесь улучшить поиск по id с помощью следующих комбинаций:
$('tagName#someId')
$('#wrapId #someId')

Это только замедлит выполнение поиска.

2. Используйте результат поиска элементов повторно


Не следует производить поиск одних и тех же элементов снова и снова, это достаточно дорогостоящая процедура, даже если вы используете самый быстрый селектор:
$('#myElement').bind('click', function(){...});
. . .
$('#myElement').css('border', '3px dashed yellow');
. . .
$('#myElement').fadeIn('slow');

В этом случае, jQuery каждый раз будет осуществлять поиск элемента с идентификатором myElement. Гораздо разумнее будет найти элемент один раз, сохранить его, а затем применять к нему необходимые операции:
var myElement = $('#myElement');
. . .
myElement.bind('click', function(){...});
. . .
myElement.css('border', '3px dashed yellow');
. . .
myElement.fadeIn('slow');


Если на протяжении работы вашего скрипта часто используются одни и те же элементы, то будет разумно найти эти элементы только один раз и сохранить результат в глобальной переменной:
window.elements;
function init()
{
  elements = $('#someId tagName.someClass');
}

Правда, иногда, необходимо совершать манипуляции с разными группами элементов, которые, однако, являются связанными. Например, это могут быть элементы формы, с которыми необходимо совершать много манипуляций. В таком случае, нам постоянно придется искать нужные элементы:
$('#myForm input:checkbox') // все флажки
$('#myForm input:text') // все текстовые поля
$('#myForm input:text[value != ""]') // все непустые текстовые поля
. . .

Вместо этого, можно найти все элементы формы один раз, и при необходимости доставать оттуда необходимые:
var inputs = $('#myForm input');
inputs.filter(':checkbox') // найдем все флажки
inputs.filter(':text') //найдем все текстовые поля
inputs.filter(':text[value != ""]') // найдем все непустые текстовые поля
. . .

Или, вам может потребоваться совершать много манипуляций с элементами списка, в том числе удалять и добавлять их. В таком случае, «кэшировать» элементы списка не будет хорошей идеей, поскольку их состав будет постоянно меняться, а «кэш» оказываться неактуальным. Однако, можно сохранить объект самого списка в глобальной переменной, что тоже значительно сократит вычислительные затраты:
myList = $('#myList');
. . .
myList.find('li:first').remove(); // найдем и удалим первый элемент списка
myList.find('li.showed').hide(); // скроем все элементы списка с классом showed


3. Избегайте лишних манипуляций c DOM


Основной идеей здесь является то, что если вы хотите внести ряд изменений на странице (добавить/изменить элемены), проделывайте эти манипуляции локально и только после этого вносите изменения в DOM. Например, если вы хотите добавить в список сто новых элементов, то ошибочным будет делать это поэлементно:
var top_100_list = [...]; // содержимое новых элементов
$mylist = $('#mylist'); // необходимый список

for (var i=0; i< top_100_list.length; i++)
  $mylist.append('<li>' + top_100_list[i] + '</li>');

гораздо эффективнее будет вставить сразу все элементы:
var top_100_list = [...]; // содержимое новых элементов
var li_items = ""; // вставляемый html-текст
$mylist = $('#mylist'); // необходимый список

for (var i=0; i< top_100_list.length; i++)
  li_items += '<li>' + top_100_list[i] + '</li>';
$mylist.append(li_items);

Еще больший выигрыш можно получить, если группа вставляемых элементов окажется «обернутой» одним элементом. Поэтому, если бы у нас была задача заменить содержимое списка сотней новых элементов, то самым оптимальным, был бы такой вариант:
var top_100_list = [...]; // содержимое новых элементов
var new_ul = "<ul id='mylist'>"; // вставляемый html-текст
$mylist = $('#mylist'); // необходимый список

for (var i=0; i< top_100_list.length; i++)
  new_ul += '<li>' + top_100_list[i] + '</li>';
new_ul += "</ul>";
$mylist.replaceWith(new_ul);


Изменять элементы локально, поможет метод clone(), который создает копии элементов, вместе со всем их содержимым. Произведя все необходимые изменения с копиями, можно вставить их обратно в DOM, вместо старых версий (это можно сделать с помощью метода replaceWith()).

4. Используйте делегирование событий


Иногда, приходится устанавливать одинаковые обработчики событий на большую группу элементов. Например, может потребоваться установить обработчики нажатия мышью, элементам списка. В таких случаях, вместо того, чтобы устанавливать обработчики на каждый элемент списка, можно установить один обработчик на сам список. Как известно, стандартные события javascript, вызванные на каком-либо элементе, затем вызываются на всех его предках (родительском элементе, затем прародительском и.т.д). Поэтому, после того, как событие произойдет на конкретном элементе списка, оно будет вызвано на объекте самого списка. Понять, у кого именно произошло событие, поможет передаваемый в обработчик объект event, а точнее, его свойство event.target. Оно всегда содержит DOM-объект первоначального источника события:
$('#myList').click(function(event){
  $(event.target).addClass('clicked'); // добавим нажатому элементу класс clicked
});
Tags:
Hubs:
+80
Comments151

Articles

Change theme settings