Опубликован: 16.06.2010 | Уровень: специалист | Доступ: платный
Лекция 9:

Практическое приложение

< Лекция 8 || Лекция 9: 12345678

8.7.2. Кэш

Внутреннее кэширование

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

Ситуация следующая: вы работаете со списком, у вас есть один из элементов li. Для того, чтобы получить все элементы, включая текущий, надо выбрать всех братьев (все, у кого родитель — это родитель текущего) этого элемента и добавить его самого:

$("#id").siblings().add("#id")

Так как он — прошлый элемент, с которым работали в цепочке вызовов, мы можем взять его из КЭШа:

$("#id").siblings().andSelf()

Конечно, в данном конкретном случаи быстрее было бы сделать

$("#id").parent().children()

Потому что siblings — это и есть выбор всех детей родителя. Но принцип использования этот пример иллюстрирует нормально.

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

var elt = $("#id");
elt.children().css({/**/})
elt.click();

Можно после работы с детьми вернуться обратно к родителю и работать с ним дальше:

$("#id").children().css({/**/}).end().click()

Кэширование селекторов

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

for(var i=0;i<1000;i
$("ul").append=""("<li>"+i""/

Все работает и выглядит красиво, но и это можно оптимизировать. Если вынести выборку за пределы цикла, добавление новых элементов будет проходить быстрее:

var elts = $("ul");
for(var i=0;i<1000;i
  elts.append=""("<li>"+i+"</li>")

Буферизация

Но этот код можно заставить работать еще быстрее! Каждый раз, делая append, мы заставляем обновиться DOM-дерево и заставляем браузер перерисовать страницу. Этого можно избежать, придерживая вставку в DOM-дерево.

var str = "";
for(var i=0;i<1000;i
  str += ""<li>"+i+"</li>"
$("ul").html(str);

Дело в том, что функции для работы с DOM-деревом у jQuery самые "тяжелые" (http://mabp.kiev.ua/2009/03/29/jquery-profiling/). Это объясняется просто. Все html-ноды, на которые повешены события через jQuery, имеют в себе атрибут с объектом jQuery. При удалении этих нод нужно следить, чтобы не было утечек памяти, и удалять эти атрибуты перед удалением ноды. В результате функции html и text вызывают функции полной очистки и только потом вставки нового содержимого:

jQuery(DOMElement).empty().append(text)

Функция empty выбирает все ноды и по очереди удаляет:

jQuery(DOMElement).children().remove()

А функция remove уже заботится, чтобы из элементов были удалены все дополнительные данные и события.

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

Создание "на лету"

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

$("<div></div>")

или

$("<div/>")

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

$("<div>text</div>")

И не создавать, а потом добавлять текст:

$("<div/>").text("text")

Но это не каcается создания атрибутов, для них используются намно- го более "легкие" функции attr/css/addClass (http://mabp.kiev.ua/2009/03/29/jquery-profiling/), вот тут-то и имеет смысл вместо

$("<div style='background:red;'/>")

писать

$("<div/>").css({background:'red'});

— это даст небольшой, но выигрыш.

8.7.3. События

Множественные события

$(window).bind("resize load",null,function(){
$("#id").css({width:document.clientWidth})
});

Только при этом не забываем, что поведение IE8 не соответствует стандартам, и при загрузке страницы сначала происходит событие resize, а только потом load.

То же самое корректно и в обратную сторону:

$(window).unbind("resize load");

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

Одно событие на много элементов

Если случается повесить события на длинный список:

var ul = $("<ul/>");
for(var i=0,j=1000;i<j;i++)
  $("<li>"+i+"</li>").click(function(e){
    alert(this.innerHTML);
  }).appendTo(ul);
ul.appendTo("body");

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

var str = "";
for(var i=0,j=1000;i<j;i
  str += ""<li>"+i+"</li>";
$("<ul/>")
  .append(str)
  .click(function(e){
    alert(e.target.innerHTML);
  })
  .appendTo("body");
< Лекция 8 || Лекция 9: 12345678
Ольга Артёмова
Ольга Артёмова

Доброго времени суток!

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

Сертификация: оптимизация и продвижение web-сайтов.

Ярославй Грива
Ярославй Грива
Россия, г. Санкт-Петербург
Ёдгор Латипов
Ёдгор Латипов
Таджикистан, Кургантепа