На днях вышла новая версия популярной JavaScript-библиотеки jQuery, она пополнела почти на 13 КБ минимизированного кода. Что же даст нам этот прирост в весе?
Значительное увеличение скорости исполнения популярных методов
Многие из часто используемых методов jQuery были в значительной степени изменены в jQuery 1.4. При анализе кода мы обнаружили, что мы могли бы значительно улучшить производительность jQuery: мы заметили, что в библиотеке выполняется слишком много вызовов внутренних функций, и решили поработать над упрощением кода.
В jQuery 1.4 мы значительно снизили сложность наиболее популярных методов. Полная информация об их производительности находится ниже по тексту.
Простые функции установки значений (setter)
Теперь вы можете передать функцию в качестве аргумента в метод .attr()
, и возвращаемое этой функцией значение будет установлено в качестве соответствующего атрибута. Возможность установки значений с помощью функций реализована во следующих методах: .css()
, .attr()
, .val()
, .html()
, .text()
, .append()
, .prepend()
, .before()
, .after()
, .replaceWith()
, .wrap()
, .wrapInner()
, .offset()
, .addClass()
, .removeClass()
и .toggleClass()
.
Кроме того, для следующих функций, в качестве второго параметра функции передается текущее значение: .css(), .attr(), .val(), .html(), .text(), .append(), .prepend(), .offset(), .addClass(), .removeClass() и .toggleClass().
Например, можно написать так:
// найти все амперсанды в тегах A и обернуть тегом span $('a').html(function(i,html){ return html.replace(/&/gi,'<span class="amp">&</span>'); }); // Добавить какую-либо информацию к тегам A $('a[target]').attr("title", function(i,title){ return title + " (Opens in External Window)"; });
Атрибуты (Attributes)
Улучшена производительность функций .css()
и .attr()
.
Возможность установки значений в методе .attr() с помощью функций
Кроме использования функций для установки значений в методе .attr(), вы также можете использовать текущее значение атрибута в этой функции.
jQuery('<img src="enter.png" alt="введите Ваше имя" />') .attr("alt", function(index, value) { return "Пожалуйста, " + value; });
.val( Function )
<input class="food" type='text' data-index="0" /> <input class="food" type='text' data-index="1" />
jQuery("input:text.food").hide(); jQuery("<ul class='sortable'><li>Peanut Butter</li><li>Jelly</li></ul>") .sortable() .bind("endsort", function() { $(":text.food").val(function() { return $("ul.sortable li:eq(" + $(this).attr("data-index") + ")").text(); }); });
Теперь метод .text() работает с текстом и узлами CDATA
Ядро (Core)
Быстрое создание элементов
Теперь, когда вы создаете единственный элемент с помощью функции jQuery, вы можете передать в неё объект с атрибутами и событиями элемента:
jQuery("<div/>", { id: "foo", css: { height: "50px", width: "50px", color: "blue", backgroundColor: "#ccc" }, click: function() { $(this).css("backgroundColor", "red"); } }).appendTo("body");
Ключами этого объекта являются функции, которые будут вызваны при создании элемента, в качестве значений ключа указывается первый аргумент для функций.
.eq(-N), .get(-N)
Теперь вы можете передать отрицательные значения в методы .get()
и .eq()
. Например, вы можете выбрать второй с конца блок div
или получить доступ к элементу DOM следующим образом:
$("div").eq(-2); $("div").get(-2);
Новые функции .first() и .last()
Для удобства предусмотрены простые функции .first()
и .last()
, аналогичные .eq(0)
и .eq(-1)
соответственно.
Новый метод .toArray()
.get() возвращает массив из набора jQuery. Для большей ясности в jQuery 1.4 вы можете использовать метод .toArray()
для достижения того же эффекта. Однако, в отличие от .get()
метод .toArray()
не имеет.
jQuery() возвращает пустой набор
В jQuery 1.3 метод jQuery()
возвращал набор jQuery, содержащий только элемент document
. В jQuery 1.4 он возвращает пустой набор jQuery. Это может быть полезно для создания пустого набора и динамического добавления в него элементов. Примечание: Метод jQuery().ready()
также работает в версии 1.4, но он устарел. Пожалуйста, используйте jQuery(document).ready()
или jQuery(function(){})
.
jQuery(“TAG”)
Увеличена скорость обращения к элементам при передаче единственного тега.
jQuery(“<div>”), jQuery(“<div/>”) и jQuery(“<div></div>”)
При вызове всех трёх функций для создания элементов используется функция document.createElement
, что привело к увеличению производительности метода jQuery("<div></div>")
. Обратите внимание, что если вы указываете атрибуты в передаваемых элементах, то используется метод innerHTML
.
CSS
Производительность метода .css()
увеличена в 2 раза.
Производительность методов .addClass(), .removeClass() и .hasClass() увеличена в 3 раза.
.toggleClass() может переключать несколько классов одновременно
Теперь вы можете вызвать метод .toggleClass()
с несколькими именами классов, и все они будут переключаться.
$("div").toggleClass("current active");
Данные (Data)
.data() возвращает объект, а .data(Object) устанавливает объект
Иногда нужно работать с данными, прикрепленными к элементу в виде объекта. Часто необходимо скопировать все данные из одного элемента в другой. В jQuery 1.4 метод .data()
без параметров возвращает весь объект целиком, а .data(Object)
устанавливает объект. Имейте в виду, что объект включает события, прикрепленные к элементу, так что будьте осторожны при его использовании.
Кеш данных больше не создается, если он не нужен
jQuery uses a unique expando on DOM elements that is used to get the .data() for a particular element. jQuery now avoids creating that expando when data is looked up but no data has been added. This potentially increases performance and avoids polluting the DOM in these cases.
Эффекты (Effects)
Per-property Easing
Теперь вы можете указать функции управления анимацией (easing) для отдельных свойств элементов.
$("#clickme").click(function() { $("div").animate({ width: ["+=200px", "swing"], height: ["+=50px", "linear"], }, 2000, function() { $(this).after("<div>Анимация завершена.</div>"); }); });
События
Новый метод: jQuery.proxy()
Если вы хотите достичь того, чтобы “this” внутри функции был прочно связан с определённым значением, вы можете использовать jQuery.proxy, чтобы возвратить новую функцию с нужной областью видимости.
var obj = { name: "John", test: function() { alert( this.name ); $("#test").unbind("click", obj.test); } }; $("#test").click( jQuery.proxy( obj, "test" ) );
Множественная привязка событий
Теперь вы можете передать методу .bind()
объект, содержащий несколько событий.
$("div.test").bind({ click: function(){ $(this).addClass("active"); }, mouseenter: function(){ $(this).addClass("inside"); }, mouseleave: function(){ $(this).removeClass("inside"); } });
События `change` и `submit` унифицированы
События change
и submit
надежно работают во всех браузерах для нормальных событий и событий реального времени. Мы перекрываем нормальные события change и submit в Internet Explorer и заменяем их событиями, которые работают так же, как и во всех остальных браузерах.
Новые события: `focusin` и `focusout`
Вообще события focusin
и focusout
являются эквивалентами focus и blur, but bubble, which helps tremendously if you are writing your own event delegation behavior. Пожалуйста, заметьте, что функции `focus` и `blur` не работают с методом live()
; this was a design decision due to the DOM Events spec defining focus/blur do not bubble.
$("form").focusout(function(event) { var tgt = event.target; if (tgt.nodeName == "INPUT" && !tgt.value) { $(tgt).after("<span>nothing here</span>"); } });
Манипуляция
Производительность увеличена
Несколько методов манипуляции с DOM стали значительно быстрее в jQuery 1.4. Увеличена производительность методов .append(), .prepend(), .before() и .after().
Производительность .html()
улучшена приблизительно в 3 раза.
Скорость выполнения .remove()
и .empty()
увеличена в 4 раза.
Новый метод .detach()
Метод detach()
удаляет элемент из DOM, но не удаляет связанные обработчики событий. Этот метод подходит для временного удаления элемента с последующим его восстановлением.
var foo = $("#foo").click(function() { // do something }); foo.detach(); // foo retains event handlers foo.appendTo("body");
Новый метод unwrap()
Метод unwrap()
удаляет переданный ему элемент, оставляя его потомков без изменений. Подобно этому:
<body> <div> <p>annie</p> <p>davey</p> <p>stevie</p> </div> </body>
$('div').unwrap();
<body> <p>annie</p> <p>davey</p> <p>stevie</p> </body>
Кеширование в domManip
jQuery кэширует узлы, созданные с использованием таких методов, как jQuery("<div>")
и .after("<div>")
. Благодаря этому увеличивается производительность на страницах, на которых выполняются DOM-манипуляции со строками, использующих эти методы.
before, after, replaceWith с несвязанными узлами
Теперь вы можете применять before
, after
и replaceWith
к узлам, которые не прикреплены к DOM. Это позволит вам делать более сложные манипуляции перед вставкой законченной структуры в дерево DOM.
jQuery("<div/>").before("<p>Привет</p>").appendTo("body")
.clone(true) также клонирует и данные
В jQuery 1.3 метод .clone(true)
не клонировал данные. В jQuery 1.4 он выполняет клонирование данных, что означает и возможность клонирования событий. Он использует ту же семантику, что и jQuery.extend, так что простые объекты и массивы будут клонироваться, а пользовательские объекты нет.
Смещение (Offset)
.offset( coords | Function )
Теперь можно установить смешение элемента, причем метод offset()
, как и другие функции установки, может принимать функцию в качестве аргумента.
Организация очередей (Queueing)
Чтобы улучшить работу с очередями, мы полностью пересмотрели их организацию, отличную от стандатной fx
.
Новый метод .delay()
Метод .delay()
приводит к задержке всех дальнейших элементов в очереди на определённое количество миллисекунд. По умолчанию используется очередь эффектов fx
. Вы можете указать альтернативную (другую) очередь в качестве второго аргумента функции delay
.
$("div").fadeIn().delay(4000).fadeOut();
Queue next()
В jQuery 1.4 the function that’s called is passed in another function, as the first argument, that when called automatically dequeues the next item and keeps the queue moving.
jQuery("div").queue("ajax", function(next) { var self = this; jQuery.getJSON("/update", function(json) { $(self).html(json.text); next(); }; }).queue("ajax", function() { $(this).fadeIn(); });
.clearQueue()
Теперь очередь можно очищать. Метод .clearQueue()
удаляет все невыполненные функции из очереди, но не останавливает функции, выполняемые в данный момент. Использование .clearQueue()
без параметров приведет к очистке fx
очереди.
Селекторы (Selectors)
"#id p"
стал быстрее. Любая строка селекторов, которая начинается с идентификатора работает более оптимизированно. Селекторы [5], начинающиеся с ID, всегда будут быстрее.
Обход (Traversing)
.index(), .index(String)
Метод .index()
был переписан и стал более удобным.
Теперь вы можете получить индекс элемента по отношению к элементам того же уровня:
// получить индекс первого <li class="current"> по отношению к его "братьям": $("li.current").index()
Вы можете получить индекс элемента по отношению к текущей коллекции jQuery, передав в качестве аргумента селектор или элемент DOM:
// получить индекс <h3 id="more-info"> по отношению ко всем элементам <h3>: $("#more-info").index("h3")
Новый метод .has()
Этот метод аналогичен фильтру :has()
. Он принимает набор jQuery и возвращает те элементы из этого набора, которые содержат указанный в параметре селектор.
Новые методы .nextUntil(), .prevUntil(), .parentsUntil()
Новые методы типа "until" похожи на .nextAll()
, .prevAll()
, .parents()
, но в качестве аргумента принимают селектор, по достижении которого обход останавливается.
.add(String, Element)
Теперь метод .add()
может использовать контекст. Эта функция особенно полезна, если вы хотите добавить дополнительные элементы (например, возвращенные ajax-запросом) и затем манипулировать ими вместе с остальными элементами.
.closest(filter, DOMElement)
Метод closest
теперь может принимать в качестве второго аргумента контекст в виде DOMElement. Как правило, при использовании контекста метод closest()
работает быстрее.
Утилиты (Utilities)
jQuery.isEmptyObject()
Эта функция возвращает true
, если объект не содержит ни одного свойства. Теперь достаточно передать объект в jQuery.isEmptyObject(), и jQuery выполнит итерации по переданному объекту без каких-либо других проверок.
jQuery.isPlainObject()
jQuery.isPlainObject() возвратит true
, если объект является литералом, и false
, если объект другого типа.
jQuery.contains()
jQuery.contains() возвратит true
, если оба аргумента узлы DOM и второй аргумент находится внутри первого.
jQuery.noop
jQuery.noop — пустая функция, которая может быть использована, если вам просто требуется функция для каких-либо целей.
jQuery.unique()
В jQuery 1.4 метод jQuery.unique(), используемый разработчиками внутри библиотеки для создания набора jQuery, удаляет дубликаты из набора и возвращает остальные элементы в том же порядке, что они были и на входе.
Прочее
jQuery.browser теперь может определять тип движка браузера
Например, вы можете проверить, является ли Webkit движком браузера с помощью функции jQuery.browser.webkit
.
Улучшенная поддержка апплетов
jQuery больше не пытается присоединить события или данные к Java-апплетам (которые генерируют исключения).
Теперь для сжатия исходного кода библиотеки используется Closure Compiler вместо YUI Min
Внутренняя реорганизация кода
Одним из главных изменений в новой версии было создание более четкой и понятной кодовой базы.
Вот некоторые из изменений:
- Старый файл ‘core.js’ был разделен на ‘attribute.js’, ‘css.js’, ‘data.js’, ‘manipulation.js’, ‘traversing.js’ и ‘queue.js’.
- Событие
ready
было перемещено в core.js (так как это базовая часть jQuery). - Большая часть кода соответствует новым рекомендациям по оформлению кода jQuery.
- Логика для работы с CSS и атрибутами была разделена и стала менее запутанной.
Тестирование
В jQuery 1.4 мы исправили 207 багов (по сравнению с 97 багами в релизе версии 1.3).
Кроме того мы увеличили количество тестов с 1504 в jQuery 1.3.2 до 3060 в jQuery 1.4.
Набор тестов jQuery был на 100% пройден всеми популярными браузерами (Safari 3.2, Safari 4, Firefox 2, Firefox 3, Firefox 3.5, IE 6, IE 7, IE 8, Opera 10.10 и Chrome).
Тест нашего журнала
Тест был проведен на компьютере с характеристиками: Intel Pentium IV 3ГГц, 2ГБ RAM, ОС Windows XP Professional SP 2.
Функция | jQuery 1.3.2 | jQuery 1.4 |
---|---|---|
Opera 10.10 |
||
class | ||
addClass | 125 | 15 |
addClassMulti | 266 | 47 |
hasClass | 609 | 63 |
removeClass | 266 | 141 |
removeClassMulti | 187 | 156 |
attr | ||
css | 188 | 125 |
cssMulti | 593 | 485 |
attr | 187 | 110 |
attrMulti | 328 | 250 |
dom | ||
appendLI | 31 | 47 |
appendLIs | 188 | 125 |
appendTR | 31 | 31 |
appendTRs | 78 | 32 |
appendToA | 437 | 344 |
replaceContents | 172 | 94 |
createElement | 15 | 31 |
empty | ||
empty | 921 | 250 |
remove | 4516 | 375 |
Итог | 9138 | 2721 |
Mozilla Firefox 3.5.7 |
||
class | ||
addClass | 226 | 54 |
addClassMulti | 364 | 42 |
hasClass | 519 | 77 |
removeClass | 349 | 100 |
removeClassMulti | 280 | 103 |
attr | ||
css | 332 | 151 |
cssMulti | 971 | 542 |
attr | 241 | 175 |
attrMulti | 436 | 265 |
dom | ||
appendLI | 157 | 100 |
appendLIs | 367 | 267 |
appendTR | 168 | 38 |
appendTRs | 234 | 71 |
appendToA | 743 | 539 |
replaceContents | 539 | 185 |
createElement | 40 | 34 |
empty | ||
empty | 1509 | 328 |
remove | 7447 | 672 |
Итог | 14922 | 3743 |
Internet Explorer 8 |
||
class | ||
addClass | 343 | 157 |
addClassMulti | 563 | 188 |
hasClass | 1375 | 313 |
removeClass | 609 | 281 |
removeClassMulti | 485 | 297 |
attr | ||
css | 359 | 250 |
cssMulti | 1109 | 812 |
attr | 625 | 390 |
attrMulti | 1516 | 1094 |
dom | ||
appendLI | 187 | 140 |
appendLIs | 282 | 188 |
appendTR | 141 | 63 |
appendTRs | 172 | 93 |
appendToA | 1625 | 1329 |
replaceContents | 672 | 203 |
createElement | 47 | 31 |
empty | ||
empty | 3047 | 781 |
remove | 13781 | 3562 |
Итог | 26938 | 10172 |
Google Chrome 3 |
||
class | ||
addClass | 86 | 14 |
addClassMulti | 178 | 26 |
hasClass | 268 | 24 |
removeClass | 152 | 65 |
removeClassMulti | 97 | 43 |
attr | ||
css | 170 | 86 |
cssMulti | 669 | 403 |
attr | 120 | 88 |
attrMulti | 328 | 173 |
dom | ||
appendLI | 48 | 36 |
appendLIs | 81 | 75 |
appendTR | 45 | 25 |
appendTRs | 61 | 33 |
appendToA | 262 | 256 |
replaceContents | 200 | 87 |
createElement | 12 | 12 |
empty | ||
empty | 646 | 207 |
remove | 2583 | 344 |
Итог | 6006 | 1997 |
Apple Safari 4 |
||
class | ||
addClass | 69 | 28 |
addClassMulti | 94 | 33 |
hasClass | 293 | 49 |
removeClass | 111 | 56 |
removeClassMulti | 86 | 52 |
attr | ||
css | 176 | 99 |
cssMulti | 565 | 361 |
attr | 125 | 86 |
attrMulti | 231 | 154 |
dom | ||
appendLI | 39 | 35 |
appendLIs | 61 | 64 |
appendTR | 27 | 32 |
appendTRs | 39 | 34 |
appendToA | 242 | 257 |
replaceContents | 153 | 82 |
createElement | 10 | 9 |
empty | ||
empty | 640 | 239 |
remove | 2811 | 356 |
Итог | 5772 | 2026 |
Таким образом по производительности лидирует Chrome 3, незначительно опережая Safari 4. Браузеры Opera и Firefox догоняют их с отставанием в скорости на 136% и 187% соответственно. Как и можно было ожидать в конце плетётся IE8, показав 5-кратное отставание в производительности от лидеров. Причем сей убогий браузер в ходе тестирования на двух последних тестах несколько раз зависал.
Статья основана на публикации "jQuery 1.4 Released" [6].