Справочник функций

Ваш аккаунт

Логин:
Пароль:
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:
Убрать блок ВКонтакте навсегда

Последние темы форума

Показать новые сообщения »

Почтовая рассылка



Подписчиков: 19017
Последний выпуск: 23.04.2012

Разгоняем jQuery. Часть 1

Автор: Евгений
Источник: www.designformasters.info
18 июля 2009 года

Статей по ускорению jQuery достаточно много, но обычно они не отличаются наглядностью и подробностью, поэтому я решил провести несколько тестов и выделить, те советы по ускорению jQuery, которые действительно работают.

Кеширование

Кеширование результатов выборки заложено в типовую конструкцию применения jQuery.

Цепочка вызовов:

$('#id-of-element').attr('data-value', 'data-for-element')
                   .css('color', 'red')
                   .html('<p>html code</p>');

эквивалентна, следующему коду:

var element = $('#id-of-element');
element.attr('data-value', 'data-for-element');
element.css('color', 'red');
element.html('<p>html code</p>');

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

var el = $('#el-999-9');

for (var i = 0; i 

или обработчика события:

var el = $('#el-999-9');

$('#button').click(function(){
    el.empty()
      .html('html code');
});

Кеширование эффективно даже на примере самого быстрого селектора #id:

Код тестов:

var runCount = 100;

function testIdLoopNoCache()
{
    for (var i = 0; i 

Хороший результат, но давайте проверим селектор посложнее, например, .class1 .class2:

Разница в производительности браузеров настолько велика, что трудно показать их результаты на одном графике, поэтому выделим еще один график для самых быстрых (по крайней мере в этом тесте):

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

Минимизируйте работу с DOM

Работа с DOM по возможности должна сводиться к минимуму, например, при добавлении нескольких элементов нужно сначала объединить их код, а потом вставить одним вызовом html.

Начнем с тестов:

Код тестов:

function testAppendLi()
{
    $('#cnt').append('<ol id="list"></ol>');

    for (var i = 0; i < runCount; i++)
    {
        $('#list').append('<li>' + i + '</li>');
    }
}

function testAppendLiCacheSelection()
{
    $('#cnt').append('<ol id="list"></ol>');
    var list = $('#list');

    for (var i = 0; i < runCount; i++)
    {
        list.append('<li>' + i + '</li>');
    }
}

function testAppendAllLi()
{
    $('#cnt').append('<ol id="list"></ol>');

    var list = '';
    for (var i = 0; i < runCount; i++)
    {
        list += '<li>' + i + '</li>';
    }
    $('#list').append(list);
}

function testAppendAllUlLi()
{
    var list = '';
    for (var i = 0; i < runCount; i++)
    {
        list += '<li>' + i + '</li>';
    }
    $('#cnt').append('<ol id="list">' + list + '</ol>');
}

Тест testAppendLiCacheSelection попал на этот график с той лишь целью, чтобы показать эффект от кеширования (пусть даже очень быстрого селектора #id).

Собирайте в один элемент

Чтобы ускорить вставку большого количества элементов, их нужно обернуть в один элемент.

Обратите внимание, что тест testAppendAllUlLi работает быстрее, чем тест на чистом DOM и практически так же быстро как innerHTML, то же самое касается методов html, after и других методов с таким функционалом.

Значительное ускорение при обертывании кода в один элемент связано со способом которым jQuery внедряет html код в документ. После предварительной обработки кода, создается элемент div и код присваивается его свойству innerHTML, потом поэлементно клонируется в документ, обертывание в кода в один элемент позволяет минимизировать клонирования.

Функция $.each

Не используйте $.each там где важна скорость работы с массивом. $.each — это вызов функции в контексте объекта и последующая проверка необходимости досрочного выхода из перебора (зависит от возвращаемого функцией значения), очевидно, что простой for без лишних вызвов функций и проверок значительно быстрее $.each. Результаты тестов это подтверждают:

Разница в производительности $.each и for in применительно к объектам не столь значительна, вероятно это связано с тем, что for in не столь быстр как for и дополнительные расходы на вызов функции и if на его фоне не столь заметны.

Не используйте for in для массивов

Ну и еще раз подтверждение известного факта о медлительности цикла for in в применении к массивам:

Конкатенация строк

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

Если быстрая конкатенация нужна здесь и сейчас, можно использовать Array.push(string) и Array.join(''), но использовать их повсеместно не рекомендуется, так как конкатенация хорошо поддается оптимизации и быстрее join почти во всех современных браузерах (а если не быстрее, значит разработчики использовали не все возможности для ее оптимизации и она может ускориться в будущем).

Тот же самый график без IE6 и IE7:

Код тестов:

function testConcatenationOperator()
{
    var str = '';
    
    for (var i = 0; i 

Проблема конкатенации в IE6/7 в том, что она выполняется тривиально, для каждых двух операндов создается буфер в который они последовательно копируются, рассмотрим пример:

var s = 'str1' + 'str12' + 'str123'

В IE6/7 при выполнении первой конкатенации выделяется память под временную строку и в нее копируются строки 'str1' и 'str12', при выполнении второй конкатенации выделяется память под еще одну строку и в нее копируется строки 'str1str12' и 'str123', и т.д. При каждой конкатенации происходит выделение памяти и копирование строк.

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

Подробнее об этом можно почитать в статьях:
Performance issues with "String Concatenation" in JScript
Insight into String Concatenation in JScript

Ускорение доступа к переменным

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

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

Код теста:

var runCount = 1000000;

var globalVariable = 1;

function testGlobalVariable()
{            
    for (var i = 0; i 

Пример использования оптимизации undefined в приближенных к реальным условиях:

function testArrayLocalUndefined()
{
    var array = globalArray; //массив в котором каждый 5-й элемент определен
    var summ = 0;
    
    var undefined; //ускоритель
    
    for (var i = 0, l = array.length; i 

jQuery использует эту технику для ускорения window и undefined.

Статьи

Оставить комментарий

Оставлять комментарии могут только зарегистрированные пользователи.

Если вы не являетесь зарегистрированным пользователем, то вам необходимо зарегистрироваться. Регистрация бесплатна. Если вы уже зарегистрированы на CodeNet, то вам необходимо ввести логин и пароль в верхней (Alt-U) части страницы.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог