Высокопроизводительный JavaScript-параллакс

в 15:57, , рубрики: javascript, parallax, performance, Блог компании Hot Dot, Веб-разработка, метки: , ,

Здравствуйте!

Я — Фёдор furikuretsu Ананьев, веб-разработчик студии Hot Dot, и сегодня я дам несколько простых советов для тех, кто хочет сделать своё JS-параллакс-приложение очень и очень быстрым.

Рассказ будет основываться на опыте, полученном из создания главной страницы нашего нового сайта hotdot.pro. Эта страница разделена на несколько слайдов, при этом каждый из слайдов принимает размер окна браузера. В каждом слайде могут быть или не быть плавающие параллакс-слои. Фон страницы тоже движется по законам параллакс-слоя.

Всё начинается с JS

Первая, очевидная проблема, которую хочется решать — скрипты.

— Почему нам захочется её решать?

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

Пример:
Если в нашем параллаксе есть пять слайдов, в каждом из слайдов — в среднем по три слоя, а обновляем параллакс мы с минимально допустимой кино-частотой в 25 FPS, то ваш код, ответственный за отрисовку одного слоя, будет вызван

5 × 3 × 25 = 375 раз в секунду.

Такая математика мотивирует держать на счету каждую операцию в часто используемых местах кода.

2D-модель плавающего слоя в контейнере давно опробована, не представляет сложности для старшеклассника и в этой статье будет опущена. Что стоит отметить, однако, так это то, что для слоя применимо эмпирическое правило:

Для обновления позиции слоя достаточно двух операций:

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

— Почему это правило важно для нас?

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

Для вашего душевного состояния применимо еще одно эмпирическое правило:

Когда вы производите по две операции вместо пяти+ по 375 раз в секунду,
вы чувствуете себя гораздо лучше.

Браузер рисует быстрее вашего знакомого фрилансера, но все же недостаточно быстро

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

Мы, привыкшие к классическим приемам в 3D-движках, можем думать, что все за пределами экрана будет как-то оптимизированно убрано из очереди на отрисовку. Но оно не будет убрано.

Следствие:
Если у вас есть возможность скрывать (то есть накладывать css-правила display:none) в момент Х те элементы, которые не появляются на экране в момент Х — пожалуйста, всеми возможными путями делайте это.

В случае параллакса элементы есть слайды, и на нашу удачу определение свойства «находится за пределами экрана» довольно тривиально.

Видеокарта

  • В webkit- и gecko-браузерах вы получаете мгновенный прирост производительности, если организуете перемещение абсолютно расположенных слоев с помощью translate3d вместо left.
  • В Opera доступна только двухмерная версия — translate. В моём случае выигрыш производительности от её применения был сомнителен.
  • Internet Explorer отлично делает все остальные браузеры при использовании классического left для смещения слоев. Довольно занятно то, что в моём случае применение translate3d снижало его производительность.

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

Инвалидация

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

— Что это значит для меня на практике?

Если в процессе скольжения пользователя по нашей странице мы оставляем проигрываться какую-нибудь безобидную маленькую анимацию в далеком и даже скрытом от нас слайде, браузер запустит процесс перестройки нашей страницы и последующую перерисовку. Запустит каждый раз, когда анимация будет делать шаг. И это в то время, когда пользователь прокручивает страницу, а процессор и так старается изо всех сил двигать слои в больших количествах быстро. Частота шага, например, в JQuery — 13 миллисекунд. Brace yourselves: будет больно.

— Можно ли менять хоть что-то, пока пользователь скользит по странице?

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

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

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

Статистика

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

Высокопроизводительный JavaScript параллакс

Высокопроизводительный JavaScript параллакс

Тест был краток. Я проехал сайт слева направо, не очень торопясь. Но поэтому тест был также и очень жесток со второй версией, ведь ей надо постоянно скрывать и показывать, скрывать и показывать слайды!

Что мы видим сначала? Весь первый график залит зеленым. Очень, очень много рисования и перерисовывания каждый кадр. Огромная работа для браузера, проделанная на центральном процессоре, и очень неприятные ощущения для пользователя.

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

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

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


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

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

Автор: codingdream

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js