Как получилось так, что Javascript анимация быстрее и лучше CSS переходов? И как стало возможным, что релизы медиа-мобильных сайтов у Adobe и Google конкурируют с нативными приложениями?
В этой статье изложен детальный разбор, почему библиотеки Javascript DOM анимации, такие как Velocity.js и GSAP более производительные, чем jQuery и CSS анимация.
Щелкните по картинке и оцените возможности Javascript:
jQuery
Начнем с основ: Javascript и jQuery были ложно объединены. Javascript анимация быстрая. jQuery замедляет анимацию . Все из-за того, что анимация не была целью проекта jQuery и в нем не заложен мощный производительный движок, хотя jQuery является достаточно мощной библиотекой:
- jQuery не может избежать синхронизации DOM из-за собственного кода, который предназначен для многих вещей, выходящих за пределы анимации;
- jQuery используя много памяти, часто вызывает «сборщик мусора», что вызывает подтормаживание анимации;
- jQuery использует setInterval вместо requestAnimationFrame (RAF). См. http://stackoverflow.com/questions/7999680/why-doesnt-jquery-use-requestanimationframe и http://habrahabr.ru/post/114358/ и http://html5.by/blog/what-is-requestanimationframe/
Примеры
Чтобы избежать подтормаживания макета достаточно просто сгруппировать вместе DOM-запросы и DOM-апдейты:
var currentTop, currentLeft;
/* With layout thrashing. */
currentTop = element.style.top; /* QUERY */
element.style.top = currentTop + 1; /* UPDATE */
currentLeft = element.style.left; /* QUERY */
element.style.left = currentLeft + 1; /* UPDATE */
/* Without layout thrashing. */
currentTop = element.style.top; /* QUERY */
currentLeft = element.style.left; /* QUERY */
element.style.top = currentTop + 1; /* UPDATE */
element.style.left = currentLeft + 1; /* UPDATE */
Плавность анимации зависит от частоты кадров. Частота кадров измеряется в «кадрах в секунду» (FPS – Frame Per Second). Фильмы и видео обычно делают с частотой 24 fps – 30 fps. Чем больше это число, тем более гладкой кажется анимация. С другой стороны – чем больше FPS, тем больше нужно ресурсов процессора, что может привести к подвисанию и пропуску кадров. Т.к. у большинства экранов частота обновления составляет 60 Гц – то и fps, к которому надо стремится должен быть равен 60-ти.
Исходя из этого, можно посчитать идеальный интервал1000ms / 60(fps) = 16.7ms
Т.е. setInterval(step, 17);
И что из этого следует?
- setTimeout() и setInterval() не обращают внимание на то, что еще происходит в браузере. Страница, на которой происходит анимация, может находится на неактивной вкладке браузера. И при этом все равно будут использоваться ресурсы процессора. На данный момент только Chrome делает интервал анимации равным 1fps на скрытых вкладках.
- SetTimeout()иsetInterval()требуют перерисовки страницы не тогда, когда это делает компьютер (а он делает это регулярно). Это означает, что браузер должен синхронизировать вашу анимацию с обновлением всего экрана, и если ее частота не синхронизирована с обновлением всего экрана, это может потребовать больше вычислительной мощности. А это загрузка процессора, расход батареи мобильных устройств и дерганная анимация.
- Самая большая проблема настает, когда нужно анимировать несколько элементов сразу. Можно попытаться все это синхронизировать, но это станет очередным кошмаром в случае разноплановой анимации, происходящей одновременно.
Вместо этого, разработчики Mozilla предложили использовать функцию requestAnimationFrame (RAF), которая не требует значительной переработки существующего кода. Можно сравнить базовую реализацию RAF и setInterval:
var startingTop = 0;
/* setInterval: Runs every 16ms to achieve 60fps (1000ms/60 ~= 16ms). */
setInterval(function() {
/* Since this ticks 60 times a second, we divide the top property's increment of 1 unit per 1 second by 60. */
element.style.top = (startingTop += 1/60);
}, 16);
/* requestAnimationFrame: Attempts to run at 60fps based on whether the browser is in an optimal state. */
function tick () {
element.style.top = (startingTop += 1/60);
}
window.requestAnimationFrame(tick);
RAF делает максимально возможный толчок в производительности анимации, который можно сделать изменив всего лишь одно место в коде. RAF группирует все анимации в одном браузерномrepaint. Это экономит ресурсы процессора и позволяет вашему устройству быть быстрее и жить дольше.
Если вы используете requestAnimationFrame, все ваши анимации будут гладкими и красивыми, синхронизированными с вашим графическим процессором (GPU) и съедающими гораздо меньше ресурсов центрального процессора (CPU).
CSS переходы
CSS переходы превзошли по быстродействию jQuery благодаря переносу логики анимации непосредственно в движок браузера, который является эффективным в случаях:
- Оптимизации взаимодействия DOM и потребления памяти, чтобы избежать рывков в браузере
- Улучшения работы алгоритмов RAF
- Использовании аппаратного ускорения (используя мощности GPU для улучшения производительности анимации)
А в реальности все это может быть выполнено непосредственно средствами Javascript. GSAP делал это в течение многих лет. Velocity.js – новый анимационный движок, который основательно меняет представление о JavaScript DOM анимации, он использует не только те же методы, но и идет на несколько шагов дальше.
Уже можно смело говорить о том, что :
Во-первых, Javascript анимация может соперничать с CSS анимацией.
Во-вторых, Javascript анимация действительно может быть быстрее, чем CSS.
Недостатки CSS-библиотек:
- Переходы исчерпывают ресурсы аппаратного ускорения GPU, что приводит к рывкам и торможению в стрессовых ситуациях. Эти эффекты особенно заметны на мобильных устройствах. (В частности, эти проблемы являются результатом перенагрузки, когда данные передаются между основным потоком браузера и потоком компоновщика. У некоторых css-свойств, таких как transforms и opacity есть иммунитет к перенагрузкам.) Мнение компания Adobe по этому поводу можно прочитать здесь
- CSS переходы не работают в версиях Internet Explorer ниже 10, в результате чего возникают проблемы доступности для браузеров IE8 и IE9.
- Т.к. переходы изначально не контролируются Javascript (они просто вызываются из Javascript), то браузер не знает как оптимизировать переходы синхронизируя их с кодом в Javascript, который управляет ими.
И наоборот, библиотеки анимации Javascript могут сами решить, когда включить аппаратное ускорение, и они могут работать во всех версиях Internet Explorer, и они идеально подходят для оптимизации анимации.
Поэтому следует использовать переходы CSS тогда, когда ведется разработка исключительно для мобильных устройств и анимация состоит только их простых изменений. В таких случаях, переходы – высокопроизводительное и нативное решение, которое позволит сохранить всю анимационную логику внутри файлов стилей и избежать раздутия страницы библиотеками Javascript. Однако, если происходит разработка сложного UI интерфейса, всегда используйте анимационную библиотеку, чтобы анимация оставалась производительной и рабочий процесс был управляем. Подключение уже одной библиотеки дает фантастическое преимущество в работе в управлении css-переходами – Transit.
JavaScript Анимация
Javascript имеет большие преимущества в производительности. Но, насколько быстр может быть Javascript? Достаточно быстр, чтобы сделать насыщенную 3d-анимацию, которую можно увидеть только с WebGL. И достаточно быстр, чтобы построить мультимедийсный тизер, который можно увидеть , применив Flash или After Effects. И достаточно быстр, чтобы построить виртуальный мир, который, обычно, можно увидеть, применив canvas.
Чтобы сравнить производительность популярных библиотек анимации, в т.ч. Transit, который использует CSS-переходы, перейдем к Velocity документации.
Остается вопрос: как именно Javascript достиг такого высокого уровня производительности? Ниже приведен краткий список оптимизаций, которые Javascript анимация способна выполнить:
- Синхронизация DOM со стеком
- Кеширование значений свойств, чтобы свести к минимуму DOM запросов (это является самой большой проблемой в производительности DOM анимации)
- Кеширование преобразованных единиц измерений (например, px в %, em и пр.) через взаимосвязанные элементы за один вызов
- Пропуск обновлений стилей, когда визуально обновления будут не нужны.
В Velocity.js используется лучшее методы кеширования конечных значений анимации для повторного использования в качестве следующих стартовых значений для следующей анимации – таким образом избегая перевызова DOM:
$element
/* Slide the element down into view. */
.velocity({ opacity: 1, top: "50%" })
/* After a delay of 1000ms, slide the element out of view. */
.velocity({ opacity: 0, top: "-50%" }, { delay: 1000 });
В этом примере, Velocity уже знает, что второй вызов должен запуститься со стартовым значением прозрачности opacity: 1 и значеним top – 50%.
И наконец, давайте сравним две библиотеки – Velocity. Js и GSAP
- GSAP – быстрый, с большими возможностями анимационной платформы. Velocity представляет из себя простой инструмент для кардинального улучшения производительности UI анимации и рабочего процесса
- GSAP – коммерческая библиотека, стоит определенных денег. Velocity – библиотека с открытым исходным кодом по лицензии MIT.
- C точки зрения производительности, Velocity. Js и GSAP неразличимы в реальных проектах.
Таким образом, GSAP следует использовать тогда, когда нужен точный контроль над временем выполнения (н-р, remapping, pause/resume/seek), движение (н-р, кривые Безье) или сложная группировка. Эти особенности имеют решающее значение при разработке игр и некоторых нишевых приложений, но они менее распространены в веб-приложениях, при разработке сайтов.
Velocity.js
То что было много времени уделено GSAP не означает, что о особенностях Velocity не будет рассказано. Наоборот. В 7kb сжатого кода, Velocity не только повторяет всю фунциональность $.animate() в jQuery, но также дополняет его по части анимации, трансформации, вращения, плавности, и прокрутки.
Velocity является лучше, чем jQuery, jQuery UI, и CSS переходы вместе взятые.
Использует метод jQuery – $.queue(), и таким образом взаимодействует легко с $.animate(), $.fade() и $.delay функциями jQuery. Также синтаксис Velocity является похожим на $.animate() и не один элемент кода на странице не нуждается в изменении.
Рассмотрим Velocity.js на примере
$element
.delay(1000)
/* Use Velocity to animate the element's top property over a duration of 2000ms. */
.velocity({ top: "50%" }, 2000)
/* Use a standard jQuery method to fade the element out once Velocity is done animating top. */
.fadeOut(1000);
В Velocity сложные сцены прокрутки с 3D-анимацией могут быть созданы двумя простыми строками кода:
$element
/* Scroll the browser to the top of this element over a duration of 1000ms. */
.velocity("scroll", 1000)
/* Then rotate the element around its Y axis by 360 degrees. */
.velocity({ rotateY: "360deg" }, 1000);
Целью Velocity является оставаться лидером в производительности анимации и удобства.
Продолжение следует
еще одна очень быстрая библиотека TremulaJS https://github.com/garris/TremulaJS