[Перевод] 33 способа ускорить ваш фронтенд в 2017 году

enter image description here


Вы уже используете прогрессивную загрузку? А как насчёт технологий Tree Shaking и разбиения кода в React и Angular? Вы настроили сжатие Brotli или Zopfli, OCSP stapling и HPACK-сжатие? А как у вас обстоят дела с оптимизацией ресурсов и клиентской части, со вложенностью CSS? Не говоря уже о IPv6, HTTP/2 и сервис-воркерах.


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


Задача повышения производительности перестала быть сугубо техническим вопросом. Теперь она внедрена в общий рабочий процесс, и те или иные архитектурные решения оцениваются с точки зрения их влияния на скорость работы системы. Производительность нужно постоянно мониторить, измерять и уточнять, но с ростом сложности веба перед разработчиками возникают всё новые проблемы, затрудняющие отслеживание метрик, ведь они сильно зависят от устройств, браузеров, протоколов, типов сетей и задержки (CDN, интернет-провайдеры, кэши, прокси, файрволы, балансировщики нагрузки и серверы — всё это влияет на производительность).


Но если описывать все факторы, о которых следует помнить при улучшении производительности — с начала работы над проектом до запуска сайта, то как будет выглядеть подобный список? Ниже вы найдёте (надеюсь, беспристрастный и объективный) чек-лист по улучшению производительности фронтенда на 2017 год. Это обзор проблем, которые вам потребуется решить для уменьшения времени отклика сайта и его плавной работы.


Чек-лист


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


Подготовка и выбор целей


1. Будьте на 20% быстрее своего самого быстрого конкурента


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


Измерьте время до начала отрисовки (с помощью WebPagetest) и до первого полезного экрана (с помощью Lighthouse) на Moto G, каком-нибудь смартфоне Samsung бизнес-класса и заурядном устройстве вроде Nexus 4 (желательно в какой-нибудь открытой лаборатории) на обычных 3G-, 4G- и Wi-Fi-подключениях.


ac1fa06f3e094121b827e8c667dbebef.png
Lighthouse, новый инструмент аудита производительности, разработанный Google


Проанализируйте полученные результаты, чтобы понять, какова ситуация у ваших пользователей. Затем можете для тестирования имитировать 90-й перцентиль. Соберите данные в таблицу, срежьте 20% и поставьте себе конкретные цели (бюджет производительности). Теперь вы можете при тестировании ориентироваться на конкретные показатели. Если вы будете держать бюджет в уме и стараться «придушить» хотя бы самый маленький скрипт ради уменьшения времени до начала взаимодействия, то вы на верном пути.


enter image description here
Performance budget builder


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


2. Время отклика — 100 миллисекунд, 60 кадров в секунду


Модель производительности RAIL задаёт правильные цели: сделайте всё возможное, чтобы пользователи получали отклик раньше, чем через 100 мс после начального ввода данных. Для этого страница должна возвращать управление главному потоку не позднее чем через каждые <50 мс. В высоконагруженных зонах вроде анимации везде, где возможно, лучше ничего больше не делать, либо делать абсолютный минимум.


Кроме того, каждый кадр анимации должен завершаться менее чем за 16 мс, чтобы обеспечить частоту в 60 кадров/с (1 с ÷ 60 = 16,6 мс). Желательно — менее чем за 10 мс. Поскольку браузеру нужно время для отрисовки нового кадра, ваш код должен завершить исполнение раньше 16,6 мс. Будьте оптимистичны и с умом воспользуйтесь временем ожидания. Очевидно, что эти цели относятся к runtime-производительности, а не к производительности загрузки.


3. Первый полезный экран менее чем за 1,25 с, Speed Index ниже 1000


Хотя это может оказаться очень труднодостижимым, ваша главная цель — начало отрисовки менее чем через 1 с и значение Speed Index ниже 1000 (на быстрых подключениях). Время до первого полезного экрана не должно превышать 1250 мс. Для мобильных устройств, подключённых по 3G, считается приемлемым начало отрисовки не позднее чем через 3 с. Даже если будет чуть дольше, не страшно, но старайтесь снизить это значение.


Определите среду


4. Выберите и настройте инструменты для сборки


Не обращайте слишком много внимания на то, что сегодня считается якобы крутым. Придерживайтесь своей среды для сборки, будь то Grunt, Gulp, Webpack, PostCSS или какая-то комбинация инструментов. Пока вы достаточно быстро получаете результаты и не испытываете проблем с поддержанием процесса сборки, вы всё делаете правильно.


5. Прогрессивное улучшение


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


6. Angular, React, Ember и компания


Выберите фреймворк, позволяющий выполнять отрисовку на сервере. Обязательно измерьте время загрузки на мобильных устройствах в режимах отрисовки на серверной и клиентской сторонах, прежде чем остановиться на конкретном фреймворке (потом будет очень сложно «менять коней на переправе», и это приведёт к проблемам с производительностью). Если вы решите воспользоваться JS-фреймворком, то обязательно убедитесь, что ваш выбор — продуманный и осознанный. Разные фреймворки по-разному влияют на производительность и требуют разных подходов к оптимизации, так что нужно чётко понимать все преимущества и недостатки выбранного вами инструмента. При создании веб-приложения обратите внимание на PRPL-паттерн и архитектуру оболочки приложения.


enter image description here


PRPL расшифровывается как Pushing critical resource, Rendering initial route, Pre-caching remaining routes and Lazy-loading remaining routes on demand: передача критических ресурсов, отрисовка начального маршрута, предварительное кэширование остальных маршрутов, отложенная загрузка остальных маршрутов по запросу.


enter image description here


Оболочка приложения — это сочетание HTML, CSS и JavaScript, минимально необходимое для работы пользовательского интерфейса


7. AMP или Instant Articles?


В зависимости от приоритетов и стратегии, принятых в вашей организации, вы можете воспользоваться Google AMP или Facebook Instant Articles. Можно и без них добиться хорошей производительности, но AMP предлагает надёжный и быстрый фреймворк с бесплатной сетью доставки контента (CDN), а Instant Articles повышает производительность ваших продуктов в Facebook. Также есть возможность создавать прогрессивные веб-AMP.


8. Выбирайте CDN с умом


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


Вы обратили внимание, что CDN может обслуживать (и разгружать) ещё и динамический контент? Нет нужды ограничивать её только статическими ресурсами. Удостоверьтесь, что выбранная CDN выполняет сжатие и конвертирование контента, поддерживает умную доставку посредством HTTP/2, технологию ESI, с помощью которой статические и динамические части страниц собираются на стороне CDN (то есть в ближайшей к пользователю серверной части), и решает прочие задачи.


Оптимизация сборки


9. Установите приоритеты


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


Постройте таблицу. Определите основную функциональность для устаревших браузеров (то есть полную доступность основного контента), расширенную функциональность для современных браузеров (то есть улучшенную, полную функциональность) и дополнительные материалы (ресурсы, в которых нет необходимости и которые могут подгружаться лениво: веб-шрифты, дополнительные стили, скрипты каруселей, видеоплееры, кнопки соцсетей, крупноразмерные изображения). Подробнее об этом можно почитать в статье Improving Smashing Magazine«s Performance.


10. Используйте подход Cutting the Mustard


Он используется для передачи устаревшим браузерам основной, а современным браузерам — расширенной функциональности. Будьте строги при загрузке своих ресурсов: немедленно грузите основную функциональность, расширения — по событиям DOMContentLoaded, а дополнительные материалы — по событиям load.


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


11. Рассмотрите вопросы микрооптимизаций и прогрессивной загрузки


В ряде случаев требуется какое-то время на инициализацию приложения, прежде чем отрисовывать страницу. Вместо индикаторов загрузки лучше использовать каркасное отображение. Поищите модули и методики, позволяющие уменьшить время первичной отрисовки (например, Tree-Shaking и разбиение кода), потому что большинство проблем с производительностью относится к первичному парсингу при запуске приложения. Также используйте AOT-компилятор для переноса части клиентской отрисовки на сторону сервера, что ускорит получение достойного результата. Наконец, рассмотрите возможность применения Optimize-js для более быстрой первичной загрузки за счёт обёртывания немедленно вызываемых функций (хотя это может быть уже и необязательно).


enter image description here


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


Что лучше — рендеринг на стороне клиента или сервера? В обоих случаях необходимо настроить прогрессивную загрузку: рендеринг на стороне сервера ускорит появление первого полезного экрана, но это требует какого-то минимального JavaScript, необходимого для того, чтобы время до начала взаимодействия было близко ко времени до первого полезного экрана. Потом уже мы можем подгрузить второстепенные части приложения, по запросу или если позволяет время. К сожалению, во фреймворках обычно отсутствует понятие приоритетов, явно предоставляемых разработчикам, так что с большинством библиотек и фреймворков прогрессивную загрузку реализовать непросто. Если у вас есть время и ресурсы, то можете воспользоваться этой стратегией для существенного повышения производительности.


12. Правильно ли настроены заголовки HTTP-кэша?


Проверьте, чтобы expires, cache-control, max-age и прочие заголовки HTTP-кэша были настроены правильно. В целом, ресурсы должны кэшироваться либо на очень короткий срок (если они могут измениться), либо на неопределённый (если они статичны) — при необходимости можно поменять их версию в URL.


Чтобы избежать ревалидации fingerprinted-ресурсов, по мере возможности используйте предназначенный для них Cache-Control: immutable (по состоянию на декабрь 2016 года поддерживается только в Firefox в транзакциях https://). Можете почитать пособие по заголовкам HTTP-кэша, статью «Лучшие методики кэширования» и ещё одно пособие по HTTP-кэшированию.


13. Ограничьте влияние сторонних библиотек и асинхронно загружайте JavaScript


Когда пользователь запрашивает страницу, браузер берёт HTML и собирает DOM, затем берёт CSS и собирает CSSOM, а затем — генерирует дерево отрисовки, сопоставляя DOM и CSSOM. Если нужно обработать какой-то JavaScript, то браузер не начнёт отрисовывать страницу, пока не завершится обработка. Поэтому разработчики должны чётко «сказать» браузеру, чтобы он не ждал и сразу начинал отрисовывать. Для скриптов это делается с помощью HTML-атрибутов defer и async.


Но на практике лучше вместо async использовать defer (ради пользователей IE до версии 9 включительно, в противном случае у них могут не работать скрипты). Также рекомендуется ограничить влияние сторонних библиотек и скриптов, особенно кнопок социальных сетей и встроенных