Оптимизация главной страницы сайта Дыши Расскажу о всех этапах оптимизации, благодаря которым анимации на сайте препарата Масло Дыши почти перестали лагать. Речь пойдет о выборе технологий, предзагрузке изображений, рефакторинге, и не только.
Первая версия сайта сделана в студии ITSOFT в 2012 году. Первый редизайн был в 2014 году. Сейчас произошла смена позиционирования и расширение линейки препаратов Дыши. Если раньше акцент был на один препарат (“Масло Дыши”), то теперь у них 12 препаратов для разных случаев, симптомов и возрастов.
Что было задумано По задумке должно быть четыре основных сцены, и на третьей есть 6 симптомов, которые с технической точки зрения есть те же сцены: https://www.dropbox.com/s/ugkax3hiteacdoz/full.jpg?dl=0
Для наглядности?—?видео, как это должно работать:
Количество переходов Сразу возникла проблема переходов между сценами. У нас слева есть четыре точки, обозначающие четыре основные сцены. Если предположить, что это пагинация, и что по этим точкам можно кликать, то мы можем переходить с любой сцены на любую (исключение составляют переходы с любой сцены, кроме третьей, на один из симптомов). Сразу отмечу, что переходы “зеркальные”, то есть переход с первой сцены на вторую, и со второй на первую?—?это одна и та же анимация, только в обратном порядке.
Я насчитал 35 различных переходов: 6?—?по основным сценам, 24?—?с симптомов на каждую из основных сцен, 5?—?по симптомам (их сразу решили делать последовательными?—?для них только стрелочки “влево-вправо”; иначе было бы ещё плюс 10 переходов, суммарно?—?45). Страница с таким количеством переходов будет весить непозволительно много.
Переходы сделали последовательными, чтобы нельзя было перескочить с первой сцены сразу на последнюю, например. Это снизило количество возможных переходов до 9. Какие бы ни были в дальнейшем преобразования и оптимизации, это всегда означает вчетверо меньший вес анимаций.
Был соблазн сделать всё с помощью набора видеороликов. Но с работой видео на js есть ряд проблем. Хотелось иметь полный контроль над воспроизведением и цикличностью анимации. Этого проще было добиться, используя отдельные изображения в качестве кадров. Грубо говоря, я хотел имитировать видео, при этом имея возможность “зафиксировать” анимацию в любой момент времени, воспроизвести её в обратном порядке, и так далее. Это было важно.
Как было реализовано Использование отдельных изображений После отказа от видео, первым делом попробовал сделать анимацию с помощью набора img-элементов. Если в двух словах, то есть кучка изображений, расположенных на странице одинаково и имеющих одинаковый размер. Все изображения изначально скрыты. Анимация достигается путём последовательного отображения изображений. То есть сначала первый кадр становится видимым, затем второй (при этом первый скрывается) и так далее. Очень похоже на принцип “блокнотика” (http://cs5.pikabu.ru/post_img/2014/12/12/2/1418348412_264073150.gif).
Но вскоре появилась проблема: для одного перехода (это ~ 70–90 изображений) всё работало более-менее сносно, то для всех 9 переходов страница стала тормозить. Дело в том, что такие операции, как изменение видимости элементов на странице, приводят к перерисовке как отдельных частей, так и всей страницы целиком. Это ресурсоёмкие операции для браузера, и, так как смена кадров должна происходить довольно часто (~ 24 кадра в секунду), то в итоге процессор и графическая карта даже на достаточно мощном устройстве не справлялись с таким количеством объектов.
На разных стадиях разработки было до 1000 изображений для всех переходов. Конечно же, здесь нужна была предварительная загрузка.
Для начала я сделал самый простой вариант: изображения загружаются одно за одним до тех пор, пока не будут загружены все. В это время пользователь видит подсказку, что идёт загрузка.
Но не всё так просто. Даже если изображения весят по 5–6 Кб (в ходе разработки использовались изображения совсем низкого качества), то, перемножив, получим ~ 5–6 Мб для всех изображений. Грузится всё это добро долго. Если ждать загрузки всех изображений, то пользователь будет сидеть без дела минуту или даже две, что, конечно, не очень здорово. На моём компьютере загрузка длилась около 90 секунд.
У нас четыре основных сцены. На первой нет ничего, кроме логотипа и слогана, и хоть какой-либо контент начинается со второй сцены. Можно загрузить изображения для первой и второй сцены, и уже дать пользователю интерактив, возможность что-то потыкать/полистать/почитать. А третья и четвёртая сцены продолжат загружаться в фоне.
На данном шаге работы я измерил время загрузки самой “большой” третьей сцены (потому что она включает в себя шесть симптомов, и по сути, на неё приходится в семь раз большее количество изображений, по сравнению с остальными сценами).
Дисклеймер: время, показанное на графиках здесь и далее, а также все остальные количественные выкладки и значения, не являются на 100% точными с точки зрения статистики. Некоторые измерения, в силу ряда причин, производились лишь по одному-два раза, что недостаточно для точной объективной оценки. Тем не менее, большая часть измерений производилась достаточное количество раз, и в целом общие закономерности сохраняют свою силу.
Первоначальный вариант, когда изображения загружаются последовательно, можно оптимизировать. Дело в том, что на самом деле есть задержки между окончанием загрузки одного изображения, и началом загрузки другого. Это относится к серверной части, и вдаваться в подробности сейчас не буду. Скажу только, что эта разница может достигать сотен миллисекунд, что сравнимо с самим временем загрузки изображения. То есть, теоретически можно существенно сократить время загрузки всех изображений, до нескольких раз, если загружать изображения параллельно, а не последовательно.
Но не всё так просто. Современные браузеры позволяют загружать одновременно с одного хоста (параллельная загрузка) 6–8 файлов (до 13 для IE11). Казалось бы, надо выбрать максимально большое число, и грузить изображения “пачками” по 6–8 штук. Но, как выяснилось, именно одновременная загрузка изображений отжирает немало ресурсов компьютера. Из-за этого анимации, которые воспроизводятся в момент, когда идёт загрузка этих “пачек” изображений, начинает тормозить.
Опытным путём был найден компромисс: размер “пачки” составил 3 изображения. При таком количестве уже есть существенный выигрыш по общей скорости загрузки изображений, но при этом анимации переходов ещё не начинают сильно тормозить.
Повторное измерение скорости предзагрузки. На этот раз, чтобы охватить большее количество разных устройств и браузеров, подключил к тестированию своих коллег из студии.
Даже несмотря на то, что загрузка изображений “пачками” дала выигрыш в скорости загрузки почти в 2 раза (например, с 46 сек до 22 сек в браузере Yandex), в целом результат пока что неудовлетворительный! Хуже всего дела обстоят с Firefox. На многих устройствах анимации тормозят.
Данная технология создана, чтобы в прямом смысле рисовать какие-то объекты на “холсте”, используя js. Обычно с помощью canvas делают такие прикольные штуки: http://codepen.io/akm2/pen/rHIsa, http://codepen.io/jackrugile/pen/ohFbx, http://codepen.io/jackrugile/pen/Gving, http://codepen.io/jackrugile/pen/acAgx и др.
В примерах выше все объекты?—?программные, очень грубо их можно назвать “векторными”. Но есть у canvas возможность рисовать и “растровыми” объектами. Можно взять готовое изображение и “нарисовать” его на холсте.
Технология canvas совсем по-иному работает с процессором и видеокартой компьютера. Плюс, элементов на странице теперь не ~ 1000, а один. После перехода на canvas анимации стали плавнее, тормозов стало меньше. И даже общее время загрузки изображений улучшилось, особенно у Firefox.
Мне показалось странным, что время загрузки в Opera продолжает оставаться таким большим. Оказалось, что виной этому режим Opera Turbo, включенный в браузере по-умолчанию. Его принцип действия заключается в том, чтобы отдать пользователю оптимизированные версии картинок. Для этого он “прогоняет” эти изображения через свои сервера, на что тратится время. Вроде бы небольшое, но, так как картинок много, то это выливается в общую ощутимую задержку.
Данная технология ускоряет одновременную загрузку большого количества отдельных файлов. В нашем случае?—?изображений. Наглядный пример: http://www.http2demo.io/. Это в теории.
На практике результат оказался не так хорош, как ожидалось. Для тестов увеличил размер “пачки” изображений до 13 и до 500?—?но только для сравнения, так как при этом интерфейс страницы тормозит или даже “замирает”, и ни о каких анимациях в этот момент речи не идёт.
Вновь браузер Opera выбивается из общей статистики, из-за вышеупомянутой технологии Opera Turbo. Кстати, можно почти с полной уверенностью сказать, что технология http/2 (или, точнее, протокол https, без которого не работает http/2) “блокирует” Opera Turbo, что в нашем случае?—?плюс.
В целом, для всех браузеров наблюдается уменьшение времени загрузки, пусть и не очень большое.
Можно было предположить, что http/2 поведёт себя лучше при размере пачки 20–30 и более (500?—?это заведомо большее число, чем количество изображений для одной сцены). Однако, на практике разница была примерно постоянной.
При одном и том же размере “пачки” изображений технология http/2 даёт выигрыш до 25%, по сравнению с http/1.
На некоторых устройствах анимации всё-таки тормозили. Более того, было очевидно, что где-то есть утечки памяти, так как даже там, где анимации были плавные, после нескольких переходов от сцены к сцене, анимации тоже начинали подтормаживать.
Код необходимо было рефакторить (найти ошибки, узкие места, утечки памяти). После не самых долгих раздумий, принял решение переписать весь js код на “чистом” языке, без использования библиотеки jQuery, так как известно (http://vanilla-js.com/), что jQuery сильно проигрывает чистому языку в производительности.
Рефакторинг?—?дело хорошее, но муторное. Тем более, когда кода довольно много (для данного проекта это ~ 200 Кб неминифицированного js; навскидку?—?порядка 5000 строк кода; прим.?—?это код не только главной страницы, но и всех остальных интерфейсов на сайте).
После рефакторинга и перехода на чистый js, анимации стали воспроизводиться намного плавнее на тех устройствах, где ранее тормозили.
Я не проводил точных количественных измерений, но могу привести скриншоты, на которых показана загрузка процессора на моём стареньком домашнем ноуте, до и после оптимизации кода.
Загрузка процессора показана на синих графиках. 75 и 64?—?это температура процессора (не спрашивайте, почему такая высокая:). Нагрузка упала, температура снизилась.
Несмотря на все предыдущие оптимизации, оставались девайсы, на которых всё тормозило. Нет-нет, на них тормозило почти всё, что можно, а не только данная страница. Для этого случая сделали упрощённую версию главной страницы, где анимаций почти нет (точнее, они другого типа, гораздо менее требовательные к ресурсам компа).
Но не всё так просто. Как определить, с достаточно ли мощного устройства зашёл пользователь, или нет? Достаточная ли у пользователя скорость инета, чтобы загрузить все изображения (а это ~ 10–12 Мб в случае реальных изображений)? Если хотя бы одно из двух условий не будет соблюдено, то пользователю нет смысла показывать основную версию страницы, надо давать упрощённую.
Один из основных способов определить скорость интернет-соединения у пользователя?—?послать запрос на скачивание какого-либо файла, и замерить скорость, с которой этот файл скачался. Сказать легко, но…
Пользуясь личным опытом, я посчитал, что даже совсем маленькие файлы иногда скачиваются очень долго. Например, где-нибудь в метро можно попытаться открыть “миниатюрный” https://ya.ru/, и он будет открывать долго. Это не то же самое, когда инета нет (иначе увидели бы соответствующее сообщение при попытке открыть сайт). Значит, начинать проверку скорости надо с самых малых размеров файлов.
Я открыл фотошоп и нарисовал первую картинку ~ 10 Кб (https://itsoft.ru/speed-test/speed-test-10kb.png). С помощью js определятся время загрузки, скорость измеряется в первый раз. Если инет нормальный (> 250 Кбит/с), то грузится картинка побольше, ~ 52 Кб (https://itsoft.ru/speed-test/speed-test-52kb.png), и скорость определяется второй раз. Если и теперь инет позволяет (> 1500 Кбит/с), то грузится третья картинка, ~ 158 Кб (https://itsoft.ru/speed-test/speed-test-158kb.png), и определяется “окончательная” скорость.
Почему не грузить сразу большую картинку? Как раз-таки потому, что в таком случае мы слишком долго будем определять плохой инет. Почему я подгружаю файлы 10, 52 и 158 Кб, но не больше? Потому что моей задачей стоит определить скорость достаточно быстро, чтобы пользователь практически не заметил никаких задержек.
Работу скрипта по определению скорости интернета можно посмотреть здесь:
https://itsoft.ru/speed-test/speed-test--v4.php
“Эталонные” сервисы определения скорости интернета
Собственные наработки всегда надо сравнивать с проверенными решениями. Для себя я обозначил три сервиса, с результатами которых я сверялся в ходе работы:
Кстати, “эталонные” тесты могут выдавать разные результаты. Чего-то универсального и на 100% объективного скорее всего нет. Принцип действия большинства “эталонных” сервисов: скачать очень большой файл, поделить размер файла на время его загрузки и получить скорость инета. Чем больше файл, тем меньше погрешность, связанная с пингом, временем на коннект и прочими микропроблемами интернет-соединения.
Спидтест работает по тому же принципу?—?сначала определяется приблизительная скорость (грубая оценка), а затем начинается полноценный тест скорости.
У Яндекса файл, с помощью которого определяется скорость, весит ~ 80 Мб (http://cache-mskm905.cdn.yandex.net/internetometr.download.cdn.yandex.net/bigfile.png). Я не проверял, как именно работает Яндекс для мобильных устройств и для мобильного интернета, когда скорость очень и очень мала, да и само соединение не всегда стабильно. Но, полагаю, что они не дураки и тоже знают о подобной проблеме, и каким-либо образом её решают.
2ip работает так, как и я сделал свой скрипт (на тот момент я ещё не подглядывал в этот сервис, а типа сам родил эту мысль)?—?сначала скачивается мелкий файл, ~ 270 Кб (http://sp.2ip.ru/300px.png), затем файл побольше, ~ 1.2 Мб (http://sp.2ip.ru/600px.png), затем ещё больше, ~ 5 Мб (http://sp.2ip.ru/1200px.png), и ещё, ~ 9.2 Мб (http://sp.2ip.ru/1600px.png). И далее уже или усредняется, или итоговая скорость берётся, не знаю точно.
Здесь всё более-менее просто. Берём одну из тех картинок, которая у нас используется в анимациях, и пробуем… Воспроизвести анимацию. То есть, создаётся элемент canvas, на нём “рисуется” изображение. Измеряется время, за которое изображение было отрисовано. Если поделим 1000 на это время, то получим значение FPS (кол-во кадров в секунду). Нормальное значение FPS для плавного отображения анимаций: от 25–30 и выше.
Работу скрипта по определению производительности можно посмотреть здесь:
https://itsoft.ru/speed-test/perf-test.php
С одной стороны, одно от другого не зависит: может быть нормальная производительность при плохом интернете, и наоборот. Но если запустить оба теста одновременно, они будут влиять на результаты друг друга. Поэтому запускать их последовательно?—?необходимость. Это ведёт к увеличению суммарного времени тестов, но, увы, от этого не уйти.
Работу обоих скриптов вместе можно посмотреть здесь:
https://itsoft.ru/speed-test/device-test.php
Заключение Мы прошли путь от страницы, которая напрочь “вешает” браузер, до более-менее приемлемого результата. Плюс fallback в виде более лёгкого варианта страницы. Опробованы разные средства оптимизации, и каждое из них вносит свой вклад в итоговый результат.
Доволен ли я текущим состоянием главной страницы сайта Дыши? С одной стороны?—?да. С другой?—?я думаю, что существуют и другие средства, с помощью которых можно ещё лучше оптимизировать страницу. Время покажет, так как работа над сайтом продолжается. Некоторые соображения уже есть.
P.S. На момент написания статьи сайт представляет из себя промежуточную версию, в которой нет адаптива и плохое качество изображений на главной странице (это отдельная тема, связанная больше с общим размером изображений на странице). Эти и другие доработки будут реализованы на следующем этапе проекта.
Автор: Тимур Билалов,
Thanks to Alexander Nedzelsky.
Проведите конкурс среди участников CMS Magazine
Узнайте цены и сроки уже завтра. Это бесплатно и займет ≈5 минут.