Улучшение производительности вашего HTML5-приложения

Введение

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

В любом случае, когда вы работаете с анимацией, становится чрезвычайно важно, чтобы пользователи воспринимали эту анимацию как плавную. Нам нужно осознать, что плавность анимации невозможно добиться простым увеличением количества кадров в секунду сверх любого когнитивного порога. Наш мозг, к сожалению, умнее этого. Вы узнаете, что настоящие 30 кадров анимации в секунду (fps) намного лучше, чем 60 кадров в секунду с несколькими кадрами, пропущенными посередине. Люди ненавидят неровности.

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

Стратегия

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

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

Визуальная точность++ с HTML5

Аппаратное ускорение

Аппаратное ускорение — важная веха в обеспечении общей производительности рендеринга в браузере. Общая схема состоит в том, чтобы перенести задачи, которые в противном случае выполнялись бы основным процессором, на графический процессор (GPU) графического адаптера вашего компьютера. Это может привести к значительному увеличению производительности, а также снизить потребление ресурсов на мобильных устройствах.

Эти аспекты вашего документа могут быть ускорены с помощью графического процессора.

  • Композитинг общего макета
  • CSS3-переходы
  • CSS3 3D-преобразования
  • Рисунок на холсте
  • 3D-рисование WebGL

Хотя ускорение Canvas и WebGL являются функциями специального назначения, которые могут не применяться к вашему конкретному приложению, первые три аспекта могут помочь практически любому приложению стать быстрее.

Что можно ускорить?

Ускорение графического процессора работает путем перегрузки четко определенных и конкретных задач на специальное оборудование. Общая схема такова, что ваш документ разбивается на несколько «слоев», которые инвариантны к ускоряемым аспектам вашей страницы. Эти слои визуализируются с использованием традиционного конвейера рендеринга. Затем графический процессор используется для объединения слоев на одну страницу, применяя «эффекты», которые можно ускорять на лету. Возможный результат заключается в том, что объект, анимируемый на экране, не требует ни одного «переразметки» страницы во время анимации.

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

Хотя это работает, браузер на самом деле не знает, что вы выполняете что-то, что должно восприниматься человеком как плавная анимация. Подумайте, что произойдет, если вы добьетесь того же визуального вида, используя вместо этого переходы CSS3:

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

Для Chrome есть два полезных флага командной строки, которые помогут отладить ускорение графического процессора:

  1. --show-composited-layer-borders показывает красную рамку вокруг элементов, которыми манипулируют на уровне графического процессора. Хорошо подходит для подтверждения того, что ваши манипуляции происходят на уровне графического процессора.
  2. --show-paint-rects все изменения, не связанные с графическим процессором, закрашиваются, и это создает светлую рамку вокруг всех перерисованных областей. Вы можете увидеть, как браузер оптимизирует области рисования в действии.

Safari имеет аналогичные флаги времени выполнения , описанные здесь .

CSS3-переходы

CSS-переходы делают анимацию стиля тривиальной для всех, но они также являются функцией повышения производительности. Поскольку переход CSS управляется браузером, точность его анимации может быть значительно улучшена, а во многих случаях ускорена аппаратно. В настоящее время в WebKit (Chrome, Safari, iOS) есть аппаратное ускорение преобразований CSS, но оно быстро появится и в других браузерах и платформах.

Вы можете использовать события transitionEnd , чтобы создать сценарии для мощных комбинаций, хотя сейчас захват всех поддерживаемых событий завершения перехода означает наблюдение за webkitTransitionEnd transitionend oTransitionEnd .

Многие библиотеки теперь представили API-интерфейсы анимации, которые используют переходы, если они присутствуют, и в противном случае возвращаются к стандартной анимации в стиле DOM. scripty2 , переход YUI , улучшенная анимация jQuery .

CSS3-перевод

Я уверен, что вам уже приходилось анимировать положение элемента по осям x/y на странице. Вероятно, вы манипулировали свойствами left и top встроенного стиля. С помощью 2D-преобразований мы можем использовать функцию translate() , чтобы воспроизвести это поведение.

Мы можем объединить это с анимацией DOM, чтобы использовать все возможное.

<div style="position:relative; height:120px;" class="hwaccel">

  <div style="padding:5px; width:100px; height:100px; background:papayaWhip;
              position:absolute;" id="box">
  </div>
</div>

<script>
document.querySelector('#box').addEventListener('click', moveIt, false);

function moveIt(evt) {
  var elem = evt.target;

  if (Modernizr.csstransforms && Modernizr.csstransitions) {
    // vendor prefixes omitted here for brevity
    elem.style.transition = 'all 3s ease-out';
    elem.style.transform = 'translateX(600px)';

  } else {
    // if an older browser, fall back to jQuery animate
    jQuery(elem).animate({ 'left': '600px'}, 3000);
  }
}
</script>

Мы используем Modernizr для проверки возможностей CSS 2D-преобразований и CSS-переходов, если да, то мы собираемся использовать трансляцию для смещения позиции. Если это анимировано с использованием перехода, есть большая вероятность, что браузер сможет аппаратно ускорить его. Чтобы дать браузеру еще один толчок в правильном направлении, мы воспользуемся «волшебной пулей CSS» сверху.

Если возможности нашего браузера ограничены, мы вернемся к jQuery для перемещения нашего элемента. Вы можете воспользоваться плагином jQuery Transform от Louis-Remi Babe, чтобы сделать все это автоматически.

window.requestAnimationFrame

requestAnimationFrame был представлен Mozilla и доработан WebKit с целью предоставить вам собственный API для запуска анимации, будь то на основе DOM/CSS, <canvas> или WebGL. Браузер может оптимизировать одновременную анимацию в единый цикл перекомпоновки и перерисовки, что обеспечивает более высокую точность анимации. Например, анимация на основе JS, синхронизированная с переходами CSS или SVG SMIL. Кроме того, если вы запускаете цикл анимации на невидимой вкладке, браузер не будет поддерживать его работу , что означает меньшее использование ЦП, графического процессора и памяти, что приводит к значительному увеличению времени автономной работы.

Дополнительные сведения о том, как и зачем использовать requestAnimationFrame , см. в статье Пола Айриша requestAnimationFrame для умной анимации .

Профилирование

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

Профилирование JavaScript

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

Общее время выполнения функции — это общее время, необходимое для ее выполнения сверху вниз. Чистое время выполнения — это общее время выполнения минус время, необходимое для выполнения функций, вызванных из функции.

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

Для получения более подробной информации ознакомьтесь с документацией Chrome Dev Tools по профилированию .

ДОМ

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

function drawArray(array) {
  for(var i = 0; i < array.length; i++) {
    document.getElementById('test').innerHTML += array[i]; // No good :(
  }
}

Например, в приведенном выше коде практически не тратится время на выполнение реального JavaScript. По-прежнему весьма вероятно, что функция drawArray появится в ваших профилях, поскольку она очень расточительно взаимодействует с DOM.

Секреты и уловки

Анонимные функции

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

$('.stuff').each(function() { ... });

переписать на:

$('.stuff').each(function workOnStuff() { ... });

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

Профилирование длинных функций

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

  1. Правильный метод: выполните рефакторинг кода, чтобы исключить длинные функции.
  2. Зловещий метод доведения дела до конца: добавляйте в свой код операторы в виде именованных самовызывающих функций. Если вы будете немного осторожны, это не изменит семантику и приведет к тому, что части вашей функции будут отображаться в профилировщике как отдельные функции: js function myLongFunction() { ... (function doAPartOfTheWork() { ... })(); ... } Не забудьте удалить эти дополнительные функции после завершения профилирования; или даже используйте их в качестве отправной точки для рефакторинга вашего кода.

Профилирование DOM

Последние инструменты разработки Chrome Web Inspector содержат новый «Просмотр временной шкалы», который показывает временную шкалу низкоуровневых действий, выполняемых браузером. Вы можете использовать эту информацию для оптимизации операций DOM. Вам следует стремиться сократить количество «действий», которые браузер должен выполнять во время выполнения вашего кода.

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

Профилирование DOM

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

Дополнительная информация о представлении временной шкалы. Альтернативным инструментом для профилирования в Internet Explorer является DynaTrace Ajax Edition .

Стратегии профилирования

Выделить аспекты

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

  1. Время запуска (активируйте профилировщик, перезагрузите приложение, дождитесь завершения инициализации, остановите профилировщик.
  2. Нажмите кнопку и последующую анимацию (запустите профилировщик, нажмите кнопку, дождитесь завершения анимации, остановите профилировщик).
Профилирование графического интерфейса

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

Программный интерфейс

Также имеется программный интерфейс для активации отладчика. Это позволяет точно контролировать, когда начинается и когда заканчивается профилирование.

Начните профилирование с помощью:

console.profile()

Прекратите профилирование с помощью:

console.profileEnd()

Повторяемость

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

  1. Несвязанный таймер в вашем приложении, который срабатывает, пока вы измеряете что-то еще.
  2. Сборщик мусора делает свою работу.
  3. Еще одна вкладка в вашем браузере, выполняющая тяжелую работу в том же рабочем потоке.
  4. Другая программа на вашем компьютере использует процессор, что замедляет работу вашего приложения.
  5. Внезапные изменения гравитационного поля Земли.

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

Измеряйте, улучшайте, измеряйте

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

Стратегии оптимизации

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

Общей темой повышения скорости работы веб-клиентских приложений является минимизация взаимодействия с DOM. Хотя скорость движков JavaScript выросла на порядок, доступ к DOM не стал быстрее с той же скоростью. Это также по очень практическим причинам никогда не произойдет (такие вещи, как макетирование и рисование на экране, просто требуют времени).

Кэшировать узлы DOM

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

До:

function getElements() {
  return $('.my-class');
}

После:

var cachedElements;
function getElements() {
  if (cachedElements) {
    return cachedElements;
  }
  cachedElements = $('.my-class');
  return cachedElements;
}

Кэшировать значения атрибутов

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

До:

setInterval(function() {
  var ele = $('#element');
  var left = parseInt(ele.css('left'), 10);
  ele.css('left', (left + 5) + 'px');
}, 1000 / 30);

После: js var ele = $('#element'); var left = parseInt(ele.css('left'), 10); setInterval(function() { left += 5; ele.css('left', left + 'px'); }, 1000 / 30);

Выведите манипуляции с DOM из циклов

Циклы часто являются горячей точкой для оптимизации. Попробуйте подумать о том, как отделить фактическую обработку чисел от работы с DOM. Часто можно выполнить расчет, а затем, после его завершения, применить все результаты за один раз.

До:

document.getElementById('target').innerHTML = '';
for(var i = 0; i < array.length; i++) {
  var val = doSomething(array[i]);
  document.getElementById('target').innerHTML += val;
}

После:

var stringBuilder = [];
for(var i = 0; i < array.length; i++) {
  var val = doSomething(array[i]);
  stringBuilder.push(val);
}
document.getElementById('target').innerHTML = stringBuilder.join('');

Перерисовка и перекомпоновка

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

  • Этап 1. Прочтите значения DOM, необходимые для вашего кода.
  • Этап 2. Изменение DOM

Старайтесь не программировать такой шаблон, как:

  • Этап 1. Чтение значений DOM
  • Этап 2. Изменение DOM
  • Этап 3: Узнайте больше
  • Этап 4: Измените DOM где-нибудь еще.

До:

function paintSlow() {
  var left1 = $('#thing1').css('left');
  $('#otherThing1').css('left', left);
  var left2 = $('#thing2').css('left');
  $('#otherThing2').css('left', left);
}

После:

function paintFast() {
  var left1 = $('#thing1').css('left');
  var left2 = $('#thing2').css('left');
  $('#otherThing1').css('left', left);
  $('#otherThing2').css('left', left);
}

Этот совет следует учитывать для действий, происходящих в одном контексте выполнения JavaScript. (например, внутри обработчика событий, внутри обработчика интервала или при обработке ответа ajax.)

Выполнение функции paintSlow() сверху создает это изображение:

краскаSlow()

Переключение на более быструю реализацию дает следующее изображение:

Более быстрая реализация

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

Подробнее: Рендеринг: перерисовка, перекомпоновка/перекомпоновка, рестайлинг от Стояна Стефанова

Перерисовки и цикл событий

Выполнение JavaScript в браузере соответствует модели «цикла событий». По умолчанию браузер находится в состоянии «ожидания». Это состояние может быть прервано событиями взаимодействия с пользователем или такими вещами, как таймеры JavaScript или обратные вызовы Ajax. Всякий раз, когда фрагмент JavaScript запускается в такой точке прерывания, браузер обычно ждет его завершения, пока он не перерисует экран (могут быть исключения для очень долго выполняющихся JavaScript или в таких случаях, как окна предупреждений, которые эффективно прерывают выполнение JavaScript). ).

Последствия

  1. Если циклы анимации JavaScript выполняются дольше 1/30 секунды, вы не сможете создавать плавные анимации, поскольку браузер не будет перерисовываться во время выполнения JS. Если вы планируете также обрабатывать пользовательские события, вам нужно работать намного быстрее.
  2. Иногда бывает полезно отложить некоторые действия JavaScript на некоторое время. Например, setTimeout(function() { ... }, 0) Это фактически сообщает браузеру выполнить обратный вызов, как только цикл событий снова станет бездействующим (фактически некоторые браузеры будут ждать не менее 10 мс). Вы должны знать, что это создаст два цикла выполнения JavaScript, которые очень близки по времени. Оба могут вызвать перерисовку экрана, что может удвоить общее время, затрачиваемое на рисование. Действительно ли это вызовет две отрисовки, зависит от эвристики браузера.

Обычная версия:

function paintFast() {
  var height1 = $('#thing1').css('height');
  var height2 = $('#thing2').css('height');
  $('#otherThing1').css('height', '20px');
  $('#otherThing2').css('height', '20px');
}
Перерисовки и цикл событий

Давайте добавим некоторую задержку:

function paintALittleLater() {
  var height1 = $('#thing1').css('height');
  var height2 = $('#thing2').css('height');
  $('#otherThing1').css('height', '20px');
  setTimeout(function() {
    $('#otherThing2').css('height', '20px');
  }, 10)
}
Задерживать

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

Ленивая инициализация

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

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

Раньше: js var things = $('.ele > .other * div.className'); $('#button').click(function() { things.show() });

После: js $('#button').click(function() { $('.ele > .other * div.className').show() });

Делегирование мероприятий

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

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

В jQuery это можно легко выразить так:

$('#parentNode').delegate('.button', 'click', function() { ... });

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

Иногда может быть и обратное: вы используете делегирование событий и у вас возникают проблемы с производительностью. По сути, делегирование событий обеспечивает время инициализации постоянной сложности. Однако за проверку того, представляет ли событие интерес, приходится платить за каждый вызов этого события. Это может оказаться дорогостоящим, особенно для часто происходящих событий, таких как «наведение курсора» или даже «перемещение мыши».

Типичные проблемы и решения

То, что я делаю в $(document).ready занимает много времени.

Личный совет Мальте: никогда ничего не делайте в $(document).ready . Постарайтесь доставить ваш документ в окончательном виде. Хорошо, вам разрешено регистрировать прослушиватели событий, но только с помощью селектора идентификаторов и/или делегирования событий. Для дорогостоящих событий, таких как «mousemove», отложите регистрацию до тех пор, пока они не потребуются (событие наведения курсора мыши на соответствующий элемент).

А если вам действительно нужно что-то сделать, например сделать запрос Ajax для получения реальных данных, покажите красивую анимацию; вы можете включить анимацию в качестве URI данных, если это анимированный GIF-файл или что-то подобное.

Поскольку я добавил на страницу Flash-ролик, все работает очень медленно.

Добавление Flash на страницу всегда немного замедляет рендеринг, поскольку окончательный макет окна должен быть «согласован» между браузером и плагином Flash. Если вы не можете полностью избежать размещения Flash на своих страницах, убедитесь, что для параметра Flash «wmode» установлено значение «window» (которое используется по умолчанию). Это отключит возможность объединения HTML и Flash-элементов (вы не сможете видеть HTML-элемент, расположенный над Flash-роликом, и ваш Flash-ролик не может быть прозрачным). Это может быть неудобно, но значительно улучшит вашу производительность. Например, посмотрите, как youtube.com тщательно избегает размещения слоев над основным проигрывателем фильмов.

Я сохраняю данные в localStorage, теперь мое приложение зависает

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

Профилирование указывает на то, что селектор jQuery работает очень медленно.

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

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

  • Будьте как можно более конкретны в правой части селектора.
  • Используйте имя тега, которое вы не часто используете, в качестве самой правой части селектора.
  • Если ничего не помогает, подумайте о том, чтобы переписать все, чтобы можно было использовать селектор идентификаторов.

Все эти манипуляции с DOM занимают много времени.

Множество вставок, удалений и обновлений узлов DOM могут выполняться очень медленно. Обычно это можно оптимизировать, создав большую строку HTML и используя domNode.innerHTML = newHTML для замены старого содержимого. Обратите внимание, что это может плохо сказаться на удобстве обслуживания и может привести к созданию ссылок на память в IE, поэтому будьте осторожны.

Другая распространенная проблема заключается в том, что ваш код инициализации может создавать много HTML. Например, плагин jQuery, который преобразует поле выбора в набор элементов div, потому что это то, чего хотели дизайнеры, не зная лучших практик UX. Если вы действительно хотите, чтобы ваша страница работала быстро, никогда не делайте этого. Вместо этого доставьте всю разметку со стороны сервера в ее окончательном виде. С этим снова возникает много проблем, поэтому хорошенько подумайте, стоит ли скорость такого компромисса.

Инструменты

  1. JSPerf — тестирование небольших фрагментов JavaScript.
  2. Firebug — для профилирования в Firefox.
  3. Инструменты разработчика Google Chrome (доступны как WebInspector в Safari)
  4. DOM Monster — для оптимизации производительности DOM.
  5. DynaTrace Ajax Edition — для профилирования и оптимизации рисования в Internet Explorer.

дальнейшее чтение

  1. Google Скорость
  2. Пол Айриш о производительности jQuery
  3. Экстремальная производительность JavaScript (презентация слайдов)