- PVSM.RU - https://www.pvsm.ru -

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

enter image description here

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

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

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

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

Чек-лист

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

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

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

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

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

33 способа ускорить ваш фронтенд в 2017 году - 2
Lighthouse [5], новый инструмент аудита производительности, разработанный Google

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

enter image description here
Performance budget builder [8]

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

7. AMP или Instant Articles?

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

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

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

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

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

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

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

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

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

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

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

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

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

enter image description here

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

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

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

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

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

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

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

Но на практике лучше вместо async использовать defer [42] (ради пользователей IE [43] до версии 9 включительно, в противном случае у них могут не работать скрипты). Также рекомендуется ограничить влияние сторонних библиотек и скриптов, особенно кнопок социальных сетей и встроенных <iframe>. В качестве альтернативы можно использовать статичные кнопки соцсетей [44] (например, SSBG [45]) и статичные ссылки на интерактивные карты [46].

14. Правильно ли оптимизированы изображения?

Как можно больше используйте адаптивные изображения [47] с srcset, sizes и элементом <picture>. И заодно можете применять формат WebP для обслуживания WebP-изображений с элементом <picture> и запасным JPEG (пример кода [48]) либо использовать согласование содержания (content negotiation) (с помощью заголовков Accept). Sketch нативно поддерживает WebP, к тому же есть плагин [49] для экспорта WebP-изображений из Photoshop. Доступны и другие варианты [50].

enter image description here

Генератор Responsive Image Breakpoints Generator [51] автоматизирует создание изображений и разметки

Можно использовать клиентские хинты [52], которые сегодня начинают поддерживаться браузерами [53]. Не хватает ресурсов для создания сложной разметки для адаптивных изображений? Для автоматизации оптимизации изображений используйте Responsive Image Breakpoints Generator [51] или сервисы наподобие Cloudinary [54].

Также во многих случаях применение одних лишь srcset и sizes поможет достичь значительных результатов. В Smashing Magazine для имён изображений мы используем окончание -opt. Например, brotli-compression-opt.png; если изображение имеет такое окончание, то все в команде понимают, что картинка была оптимизирована.

15. Переходите на новый уровень оптимизации изображений

Работая над лэндинговой страницей, для которой важна молниеносная загрузка определённого изображения, убедитесь, что используете прогрессивные JPEG’и со сжатием MozJPEG [55] (это уменьшает время до начала отрисовки за счёт манипулирования уровнями сканирования), Pingo [56] для PNG, Lossy GIF [57] для GIF и SVGOMG [58] для SVG. Примените размытие к маловажным частям изображения (например, с помощью фильтра «размывка по Гауссу»), чтобы уменьшить размер файла. Можно даже уменьшить цветовую палитру или сделать приложение чёрно-белым. Для фоновых изображений при экспорте из Photoshop устанавливайте качество от 0 до 10%, этого будет совершенно достаточно.

Всё ещё недостаточно быстро? Ну, можно ещё улучшить производительность с помощью разных методик, применяемых к фоновым картинкам (1 [59], 2 [60], 3 [61], 4 [62]).

16. Оптимизированы ли веб-шрифты?

Наверняка используемые вами веб-шрифты используют глифы и прочие дополнительные символы, которые не будут использоваться. Ради уменьшения размеров файлов можете обратиться к поставщику с просьбой предоставить уменьшенный набор символов или вырезать всё лишнее самостоятельно [63], если вы используете opensource-шрифты (например, оставив лишь латинский алфавит и несколько акцентирующих глифов). Классная вещь — поддержка WOFF2 [64], а для браузеров, не поддерживающих его, можно применять WOFF и OTF. Также выберите одну из стратегий, описанных в статье Comprehensive Guide to Font Loading Strategies [65], и используйте кэш сервис-воркера для надёжного кэширования веб-шрифтов.

Нужно быстрое решение? Изучите этот материал [66], чтобы грузить шрифты в определённом порядке.

enter image description here

В статье Comprehensive Guide to Font Loading Strategies [65] описаны десятки способов улучшения доставки веб-шрифтов

Если вы не можете передавать шрифты со своего сервера и полагаетесь на сторонние хосты, то воспользуйтесь Web Font Loader [67]. Лучше использовать FOUT, чем FOIT [68]. Сразу же начните отрисовывать текст в запасной версии шрифта и подгружайте шрифты асинхронно. Для этого можно применять loadCSS [69]. Возможно, вам вообще удастся обойтись установленными в операционной системе шрифтами [70].

17. Быстро передавайте критический CSS

Чтобы браузер как можно скорее начинал отрисовывать страницу, стандартной практикой [71] является сбор всего CSS, необходимого для отрисовки первой видимой части страницы («критический CSS», или «CSS без прокрутки экрана» (above-the-fold CSS)) с последующим встраиванием в раздел <head> страницы. Это снижает количество обращений к серверу. Из-за ограниченного размера пакетов, которыми стороны обмениваются в ходе медленной начальной фазы, ваш бюджет критического CSS составляет около 14 Кб. Если вы его превысите, браузеру понадобится дополнительный roundtrip для получения стилей. Удержаться в рамках бюджета вам помогут CriticalCSS [72] и Critical [73]. Возможно, их придётся применять с каждым шаблоном. По мере возможности используйте метод условного встраивания [74], практикуемый Filament Group.

В случае с HTTP/2 критический CSS можно хранить в отдельном файле и доставлять по инициативе сервера (server push) без раздувания HTML. Суть в том, что такой тип доставки не имеет обязательной поддержки и имеет некоторые проблемы с кэшированием (см. слайд 114 в презентации [75]). Так что эффект может оказаться даже негативным [76]: сетевые буферы увеличатся в размерах, что предотвратит доставку в документ оригиналов фреймов. Из-за медленного старта TCP доставка по инициативе сервера гораздо эффективнее на горячих подключениях [77]. Возможно, вам понадобится создать механизм [78] такой доставки посредством HTTP/2, зависящий от кэша. Но помните, что новая спецификация кэширования [79] отменит необходимость вручную создавать подобные «зависящие от кэша» серверы.

18. Используйте Tree Shaking и разбиение кода для снижения полезной нагрузки

Tree Shaking [80] — это способ очистки вашего процесса сборки за счёт включения только того кода, который используется в рабочем проекте. Для исключения излишек при экспорте можете воспользоваться Webpack 2 [81], а для удаления неиспользуемых стилей из CSS — UnCSS [82] или Helium [83]. Возможно, вам будет полезно почитать о том, как писать эффективные CSS-селекторы [84], а также как избегать раздувания и повышения стоимости стилей [85].

Разбиение кода [30] — другая функция Webpack. Кодовая база делится на «чанки», которые грузятся по запросу. После того, как вы укажете точки разбиения в коде, Webpack позаботится о зависимостях и генерируемых файлах. Разбиение кода позволяет уменьшить объём данных при начальной загрузке, подгружая следующие порции кода по мере необходимости.

Обратите внимание, что Rollup [86] демонстрирует гораздо лучшие результаты по сравнению с экспортом Browserify. В этом случае вы, вероятно, захотите «пощупать» Rollupify [87], преобразующий модули ECMAScript 2015 в один большой модуль CommonJS — ведь маленькие модули могут на удивление сильно снижать производительность [88] в зависимости от выбранного упаковщика (Bundler) и модульной системы.

19. Улучшаем производительность отрисовки

С помощью ограничения CSS [89] мы можем изолировать дорогие компоненты. Например, для ограничения области видимости браузерных стилей, макета, отрисовки для скрытой навигации (paint work for off-canvas navigation) или сторонних виджетов. Убедитесь в отсутствии лагов при прокрутке страницы или при работе анимации элементов. Также проверьте, чтобы частота кадров постоянно была не менее 60 кадров/с. Если этого добиться не получается, то хотя бы удерживайте частоту в пределах от 15 до 60. Чтобы сообщать браузеру, какие элементы и свойства изменятся, используйте will-change [90] из CSS.

Также измеряйте производительность отрисовки в ходе исполнения [91] (например, в DevTools [92]). Для начала ознакомьтесь с бесплатным курсом на Udacity [93] по оптимизации отрисовки в браузере. Также можете почитать статью про анимацию с использованием GPU [94].

20. Прогрев соединения для ускорения доставки

Используйте каркасное отображение (skeleton screens) и ленивую загрузку всех дорогих компонентов, таких как шрифты, JavaScript, карусели, видео и iframe. Используйте хинты для ресурсов [95] для экономии времени на:

  • dns-prefetch [96] (ищет DNS в
    фоновом режиме),
  • preconnect [97] (просит браузер в фоновом режиме начать хендшейк для установки соединения (DNS, TCP, TLS)),
  • prefetch [98] (просит браузер запросить ресурсы),
  • prerender [99] (просит браузер отрисовать определённые страницы в фоновом режиме),
  • preload [100] (помимо прочего, заранее выбирает ресурсы без их исполнения).

Обратите внимание: на практике в зависимости от поддержки браузера вы предпочтёте preconnect, а не dns-prefetch и с осторожностью будете использовать prefetch и prerender. Последний стоит использовать только в том случае, если вы абсолютно уверены в том, куда отправится пользователь (например, пойдёт дальше по воронке продаж).

HTTP/2

21. Подготовка к HTTP/2

По мере того, как Google идёт к созданию более безопасного веба [101], и Chrome в конце концов начинает обращаться со всеми HTTP-страницами как с «небезопасными», вам придётся решать, останетесь ли вы на HTTP/1.1 или настроите HTTP/2-среду [102]. HTTP/2 уже очень хорошо поддерживается [103]. Он никуда не денется, и в большинстве случаев лучше придерживаться этого протокола. Вложения существенные, но рано или поздно это придётся сделать. Кроме того, вы можете получить сильный прирост производительности [104] благодаря сервис-воркерам и отправке данных по инициативе сервера (по крайне мере, в долгосрочной перспективе).

Обратная сторона медали: вам придётся мигрировать на HTTPS и в зависимости от того, насколько велика ваша пользовательская база на HTTP/1.1 (пользователи устаревших ОС или браузеров), придётся рассылать разные билды, для чего потребуется создать новый процесс сборки [105]. Имейте в виду: настройка миграции и нового процесса сборки может быть трудной и длительной задачей. Далее по тексту будем исходить из предположения, что вы либо переходите, либо уже перешли на HTTP/2.

22. Правильное развёртывание HTTP/2

Ещё раз: раздача ресурсов через HTTP/2 [106] потребует глубокого пересмотра привычных процессов. Вам придётся найти баланс между упаковкой модулей и параллельной загрузкой многочисленных маленьких модулей.

С одной стороны, вы можете захотеть избежать объединения ресурсов, разбив интерфейс на многочисленные мелкие модули, сжимая их в ходе сборки, ссылаясь на них в рамках scout-методики [105] и параллельно загружая. Изменение одного файла не потребует перезагрузки всей таблицы стилей или JavaScript.

С другой стороны, упаковка имеет смысл [107], поскольку отправка браузеру многочисленных маленьких JS-файлов сопряжена с определёнными проблемами. Во-первых, ухудшится сжатие. При повторном использовании словаря мы получаем выгоду от сжатия большого пакета, но не отдельных маленьких. Во-вторых, браузеры ещё не оптимизированы для подобных рабочих процессов. Например, для нескольких ресурсов Chrome запускает последовательное выполнение межпроцессных взаимодействий (IPC [108]), так что если у нас будет нескольких сотен ресурсов, то мы получим большие затраты во время исполнения в браузере.

enter image description here

Для достижения наилучших результатов с помощью HTTP/2 воспользуйтесь прогрессивной загрузкой CSS [109]

Также вы можете попытаться прогрессивно грузить CSS [109]. Очевидно, что в таком случае пользователи HTTP/1.1 окажутся в проигрыше, поэтому частью процесса развёртывания может стать генерирование и передача разных сборок разным браузерам. Это несколько усложнит процесс. Ещё вам может помочь объединение (coalescing) HTTP/2-соединений, позволяющее использовать шардинг домена без потери преимуществ HTTP/2, но на практике это труднодостижимо.

Как быть? Если вы используете HTTP/2, то разумным компромиссом может стать отправка примерно десяти пакетов (это не слишком плохо для устаревших браузеров). Поэкспериментируйте и подберите наилучший для вашего сайта вариант.

23. Убедитесь в надёжности системы безопасности вашего сервера

Все браузерные реализации HTTP/2 работают через TLS, так что вы наверняка захотите избежать предупреждений системы безопасности или дисфункции некоторых элементов на странице. Убедитесь в правильности настройки заголовков безопасности [110], закройте известные уязвимости [111] и проверьте свой сертификат [112].

Вы ещё не мигрировали на HTTPS? Тщательно изучите стандарт HTTPS-Only. Убедитесь, что все внешние плагины и отслеживающие скрипты грузятся через HTTPS, что атака через межсайтовый скриптинг невозможна, и что правильно настроены заголовки HTTP Strict Transport Security [113] и Content Security Policy [114].

24. Ваши серверы и CDN поддерживают HTTP/2?

Разные серверы и CDN могут по-разному поддерживать HTTP/2. Для проверки воспользуйтесь инструментом Is TLS Fast Yet [115]? либо проверьте выполнение вашими серверами и поддержку ими возможностей.

enter image description here

Is TLS Fast Yet [115]? позволяет узнать возможности ваших серверов и CDN при переходе на HTTP/2

25. Используется ли сжатие Brotli или Zopfli?

В прошлом году Google представил Brotli [116], новый opensource-формат данных без потерь, который сегодня широко поддерживается [117] в Chrome, Firefox и Opera. На практике Brotli получается эффективнее [118] Gzip и Deflate. В зависимости от настроек этот формат может сжиматься медленнее, но зато степень сжатия получается выше.

Однако распаковка выполняется быстро. Поскольку формат разработан Google, неудивительно, что браузеры принимают его только при посещении сайтов через HTTPS. К слову, для этого есть технические причины. Сегодня Brotli не предустанавливается на большинстве серверов, и его не так просто настроить без перекомпилированных NGINX или Ubuntu. Однако вы можете включить Brotli даже в тех CDN, которые [119] его пока не поддерживают (с помощью сервис-воркера).

В качестве альтернативы можно использовать алгоритм сжатия Zopfli, кодирующий данные в форматы Deflate, GZIP и ZLIB. При сжимании любого ресурса обычным GZIP вы выиграете от применения Deflate-кодирования, улучшенного с помощью Zopfli, потому что файлы станут на 3–8% меньше, чем при максимальном ZLIB-сжатии. Проблема в том, что сжимание будет идти примерно в 80 раз дольше. Поэтому рекомендуется применять Zopfli для тех ресурсов, которые не сильно меняются, а также для файлов, которые сжимаются один раз и многократно скачиваются.

26. Включён ли OCSP stapling?

Включив на своих серверах OCSP stapling [120], вы можете ускорить TLS-хендшейки. Протокол Online Certificate Status Protocol (OCSP) был создан в качестве альтернативы протоколу Certificate Revocation List (CRL). Они оба используются для проверки аннулирования SSL-сертификата. Однако OCSP не требует от браузера скачивать список сертификатов и потом искать в нём нужную информацию, что экономит время, затрачиваемое на хендшейки.

27. Вы уже внедрили IPv6?

В связи с исчерпанием IPv4 [121] и быстрым внедрением IPv6 в основных мобильных сетях (в США достигнут [122] порог 50-процентного внедрения) имеет смысл обновить ваш DNS до IPv6 [123]. Убедитесь, что в рамках сети обеспечивается поддержка двойного стека — это позволяет одновременно использовать IPv6 и IPv4. Имейте в виду, что IPv6 не имеет обратной совместимости. Исследования показывают, [124] что этот протокол может ускорять работу сайтов на 15% за счёт «обнаружения соседей» (NDP) и оптимизации маршрутов.

28. Вы используете сжатие HPACK?

Если вы используете HTTP/2, то проверьте, чтобы ваши серверы применяли HPACK-сжатие [125] для заголовков HTTP-откликов. Это уменьшает ненужные накладные расходы. Из-за своей новизны HTTP/2-серверы могут поддерживать спецификации не полностью, в том числе и HPACK. Можете проверить это с помощью прекрасного инструмента H2spec [126]. Работа HPACK [127].

enter image description here
H2spec [126]

29. Используются ли сервис-воркеры для кэширования и как сетевой fallback (network fallbacks)?

Никакие оптимизации производительности в рамках сети не могут сравниться с кэшем, хранящимся на пользовательском компьютере. Если ваш сайт работает через HTTPS, то изучите руководство Pragmatist’s Guide to Service Workers [128], чтобы кэшировать статические ресурсы в кэше сервис-воркера, а также сохранять резервный оффлайн-контент (или даже страницы целиком) с последующим извлечением с пользовательской машины вместо передачи по сети. Почитайте также Offline Cookbook [129] и изучите бесплатный курс на Udacity Offline Web Applications [130]. В браузерах появляется поддержка [131], а сеть в любом случае выступает в качестве резервного решения.

Тестирование и мониторинг

30. Отслеживайте предупреждения о смешанном контенте (mixed-content warnings)

Если вы недавно мигрировали с HTTP на HTTPS, от обязательно отслеживайте активные и пассивные предупреждения о смешанном контенте. Это можно делать с помощью report-uri.io [132]. Также можно сканировать HTTPS-сайт на наличие смешанного контента с помощью Mixed Content Scan [133].

31. Оптимизирован ли ваш процесс разработки?

Выберите инструмент для отладки и кликните по каждой кнопке. Убедитесь, что вы знаете, как анализировать производительность отрисовки и выводимые в консоль данные, как отлаживать JavaScript и редактировать CSS-стили. В этом выступлении [134] рассматриваются десятки неясностей и рисков в ходе отладки и тестирования с помощью инструментов разработчика.

32. Вы провели тестирование в устаревших и прокси-браузерах?

Недостаточно просто протестировать в Chrome и Firefox. Проверьте, как ваш сайт работает в устаревших и прокси-браузерах. К примеру, UC Browser и Opera Mini занимают приличную долю рынка в Азии [135] (до 35%). Измерьте среднюю скорость интернета [136] в ваших целевых странах, чтобы избежать неприятных сюрпризов. Протестируйте в условиях регулирования полосы пропускания, эмулируйте устройства с высоким значением DPI. BrowserStack [137] — вещь фантастическая, но обязательно проводите тесты и на реальных устройствах.

33. Настроен ли у вас непрерывный мониторинг?

Наличие собственного экземпляра WebPagetest [4] полезно для быстрого тестирования без ограничений. Настройте непрерывный мониторинг бюджета производительности с автоматической рассылкой предупреждений. Также настройте собственные пользовательские временные метки (user timing marks) для измерения и мониторинга специфических бизнес-метрик. Отслеживать изменение производительности можно с помощью SpeedCurve [138] и/ или New Relic [139]. Это поможет понять ограничения WebPagetest. Также обратите внимание на SpeedTracker [140], Lighthouse [5] и Calibre [141].

Быстрые результаты

У нас получился достаточно объёмный список, и оптимизация займёт какое-то время. А если у вас есть всего один час, чтобы значительно улучшить производительность? Давайте сведём наш список к десяти самым быстрорешаемым задачам. Конечно, перед началом оптимизации и по её окончании необходимо будет провести измерения, включая время начала отрисовки и значение Speed Index при 3G- и кабельном соединении.

  1. Ваша цель — начать отрисовку менее чем через одну секунду для кабельного и менее чем через три секунды – для 3G-соединения. Значение SpeedI ndex — менее 1000. Оптимизируйте время начала отрисовки и время до начала взаимодействия.

  2. Подготовьте критический CSS для ваших шаблонов и включите его в <head> (ваш бюджет — 14 Кб).

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

  4. Воспользуйтесь хинтами для ресурсов ради ускорения доставки с помощью dns-lookup, preconnect, prefetch, preload и prerender.

  5. Используйте уменьшенные наборы символов в веб-шрифтах и грузите их асинхронно (или вообще переключитесь на системные шрифты).

  6. Оптимизируйте изображения и постарайтесь использовать WebP на наиболее важных страницах (например, лэндинговых).

  7. Проверьте правильность настройки заголовков HTTP-кэша и заголовков безопасности.
  8. Включите на сервере сжатие Brotli или Zopfli. Если это невозможно, то не забудьте включить GZIP-сжатие.

  9. Если доступен HTTP/2, то включите HPACK-сжатие и начните отслеживать предупреждения о смешанном контенте. Если вы работаете через TLS, то включите OCSP stapling.

  10. По мере возможности кэшируйте такие ресурсы, как шрифты, стили, JavaScript и изображения (чем больше, тем лучше!) в кэше сервис-воркера.

Скачайте чек-лист (PDF, Apple Pages)

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

Если вам нужны альтернативные решения, обратитесь к чек-листам Дэна Раблика [144] и Джона Яблонски [145].

Поехали!

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

Автор: Badoo

Источник [146]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/javascript/237676

Ссылки в тексте:

[1] психологическому исследованию: https://www.smashingmagazine.com/2015/09/why-performance-matters-the-perception-of-time/#the-need-for-performance-optimization-the-20-rule

[2] время, необходимое для отображения: https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint

[3] время, через которое страница: https://developers.google.com/web/tools/lighthouse/audits/time-to-interactive

[4] WebPagetest: http://www.webpagetest.org/

[5] Lighthouse: https://github.com/GoogleChrome/lighthouse

[6] открытой лаборатории: https://www.smashingmagazine.com/2016/11/worlds-best-open-device-labs/

[7] таблицу: http://danielmall.com/articles/how-to-make-a-performance-budget/

[8] бюджет производительности: http://bradfrost.com/blog/post/performance-budget-builder/

[9] Модель производительности RAIL: https://www.smashingmagazine.com/2015/10/rail-user-centric-model-performance/

[10] Будьте оптимистичны: http://info.meteor.com/blog/optimistic-ui-with-meteor-latency-compensation

[11] Speed Index: https://sites.google.com/a/webpagetest.org/docs/using-webpagetest/metrics/speed-index

[12] приемлемым: https://www.soasta.com/blog/google-mobile-web-performance-study/

[13] прогрессивное улучшение: https://www.aaron-gustafson.com/notebook/insert-clickbait-headline-about-progressive-enhancement-here/

[14] отказоустойчивые: https://resilientwebdesign.com/

[15] продуманный: https://www.youtube.com/watch?v=6I_GwgoGm1w

[16] осознанный: https://medium.com/@ZombieCodeKill/choosing-a-javascript-framework-535745d0ab90#.2op7rjakk

[17] PRPL-паттерн: https://developers.google.com/web/fundamentals/performance/prpl-pattern/

[18] архитектуру оболочки приложения: https://developers.google.com/web/updates/2015/11/app-shell

[19] AMP: https://www.ampproject.org/

[20] Instant Articles: https://instantarticles.fb.com/

[21] создавать прогрессивные веб-AMP: https://www.smashingmagazine.com/2016/12/progressive-web-amps/

[22] генератор статических сайтов: https://www.smashingmagazine.com/2015/11/static-website-generators-jekyll-middleman-roots-hugo-review/

[23] платформу статического хостинга: https://www.smashingmagazine.com/2015/11/modern-static-website-generators-next-big-thing/

[24] JAMstack: https://jamstack.org/

[25] ESI: https://en.wikipedia.org/wiki/Edge_Side_Includes

[26] Improving Smashing Magazine’s Performance: https://www.smashingmagazine.com/2014/09/improving-smashing-magazine-performance-case-study/

[27] используется: http://responsivenews.co.uk/post/18948466399/cutting-the-mustard

[28] каркасное отображение: https://twitter.com/lukew/status/665288063195594752

[29] Tree-Shaking: https://medium.com/@richavyas/aha-moments-from-ngconf-2016-part-1-angular-2-0-compile-cycle-6f462f68632e#.8b9afnsub

[30] разбиение кода: https://webpack.github.io/docs/code-splitting.html

[31] AOT-компилятор: https://ru.wikipedia.org/wiki/AOT-%D0%BA%D0%BE%D0%BC%D0%BF%D0%B8%D0%BB%D1%8F%D1%86%D0%B8%D1%8F

[32] переноса части клиентской отрисовки: https://www.smashingmagazine.com/2016/03/server-side-rendering-react-node-express/

[33] сторону сервера: http://redux.js.org/docs/recipes/ServerRendering.html

[34] Optimize-js: https://github.com/nolanlawson/optimize-js

[35] необязательно: https://twitter.com/tverwaes/status/809788255243739136

[36] Прогрессивная загрузка: https://aerotwist.com/blog/when-everything-is-important-nothing-is/

[37] во фреймворках обычно отсутствует: https://aerotwist.com/blog/when-everything-is-important-nothing-is/#which-to-use-progressive-booting

[38] поддерживается только в Firefox: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control

[39] пособие по заголовкам HTTP-кэша: https://devcenter.heroku.com/articles/increasing-application-performance-with-http-cache-headers

[40] «Лучшие методики кэширования»: https://jakearchibald.com/2016/caching-best-practices/

[41] пособие по HTTP-кэшированию: https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=en

[42] вместо async использовать defer: http://calendar.perfplanet.com/2016/prefer-defer-over-async/

[43] ради пользователей IE: https://github.com/h5bp/lazyweb-requests/issues/42

[44] статичные кнопки соцсетей: https://www.savjee.be/2015/01/Creating-static-social-share-buttons/

[45] SSBG: https://simplesharingbuttons.com/

[46] статичные ссылки на интерактивные карты: https://developers.google.com/maps/documentation/static-maps/intro

[47] адаптивные изображения: https://www.smashingmagazine.com/2014/05/responsive-images-done-right-guide-picture-srcset/

[48] пример кода: https://dev.opera.com/articles/responsive-images/#different-image-types-use-case

[49] плагин: http://telegraphics.com.au/sw/product/WebPFormat#webpformat

[50] Доступны и другие варианты: https://developers.google.com/speed/webp/docs/using

[51] Responsive Image Breakpoints Generator: http://www.responsivebreakpoints.com/

[52] клиентские хинты: https://www.smashingmagazine.com/2016/01/leaner-responsive-images-client-hints/

[53] начинают поддерживаться браузерами: http://caniuse.com/#search=client-hints

[54] Cloudinary: http://cloudinary.com/documentation/api_and_access_identifiers

[55] MozJPEG: https://github.com/mozilla/mozjpeg

[56] Pingo: http://css-ig.net/pingo

[57] Lossy GIF: https://kornel.ski/lossygif

[58] SVGOMG: https://jakearchibald.github.io/svgomg/

[59] 1: http://csswizardry.com/2016/10/improving-perceived-performance-with-multiple-background-images/

[60] 2: https://jmperezperez.com/medium-image-progressive-loading-placeholder/

[61] 3: https://manu.ninja/dominant-colors-for-lazy-loading-images#tiny-thumbnails

[62] 4: https://css-tricks.com/the-blur-up-technique-for-loading-background-images/

[63] вырезать всё лишнее самостоятельно: https://www.fontsquirrel.com/tools/webfont-generator

[64] поддержка WOFF2: http://caniuse.com/#search=woff2

[65] Comprehensive Guide to Font Loading Strategies: https://www.zachleat.com/web/comprehensive-webfonts/

[66] этот материал: https://pixelambacht.nl/2016/font-awesome-fixed/

[67] Web Font Loader: https://github.com/typekit/webfontloader

[68] FOUT, чем FOIT: https://www.filamentgroup.com/lab/font-events.html

[69] loadCSS: https://github.com/filamentgroup/loadCSS

[70] обойтись установленными в операционной системе шрифтами: https://www.smashingmagazine.com/2015/11/using-system-ui-fonts-practical-guide/

[71] стандартной практикой: https://www.smashingmagazine.com/2015/08/understanding-critical-css/

[72] CriticalCSS: https://github.com/filamentgroup/criticalCSS

[73] Critical: https://github.com/addyosmani/critical

[74] метод условного встраивания: https://www.filamentgroup.com/lab/performance-rwd.html

[75] презентации: http://www.slideshare.net/Fastly/http2-what-no-one-is-telling-you

[76] негативным: http://calendar.perfplanet.com/2016/http2-push-the-details/

[77] гораздо эффективнее на горячих подключениях: https://docs.google.com/document/d/1K0NykTXBbbbTlv60t5MyJvXjqKGsCVNYHyLEXIxYMv0/edit

[78] механизм: https://css-tricks.com/cache-aware-server-push/

[79] спецификация кэширования: http://calendar.perfplanet.com/2016/cache-digests-http2-server-push/

[80] Tree Shaking: https://medium.com/@roman01la/dead-code-elimination-and-tree-shaking-in-javascript-build-systems-fb8512c86edf

[81] Webpack 2: http://www.2ality.com/2015/12/webpack-tree-shaking.html

[82] UnCSS: https://github.com/giakki/uncss

[83] Helium: https://github.com/geuis/helium-css

[84] писать эффективные CSS-селекторы: http://csswizardry.com/2011/09/writing-efficient-css-selectors/

[85] избегать раздувания и повышения стоимости стилей: https://benfrain.com/css-performance-revisited-selectors-bloat-expensive-styles/

[86] Rollup: http://rollupjs.org/

[87] Rollupify: https://github.com/nolanlawson/rollupify

[88] на удивление сильно снижать производительность: https://nolanlawson.com/2016/08/15/the-cost-of-small-modules/

[89] ограничения CSS: http://caniuse.com/#search=contain

[90] will-change: http://caniuse.com/#feat=will-change

[91] производительность отрисовки в ходе исполнения: https://aerotwist.com/blog/my-performance-audit-workflow/#runtime-performance

[92] в DevTools: https://developers.google.com/web/tools/chrome-devtools/rendering-tools/

[93] бесплатным курсом на Udacity: https://www.udacity.com/course/browser-rendering-optimization--ud860

[94] анимацию с использованием GPU: https://www.smashingmagazine.com/2016/12/gpu-animation-doing-it-right/

[95] хинты для ресурсов: https://w3c.github.io/resource-hints

[96] dns-prefetch: http://caniuse.com/#search=dns-prefetch

[97] preconnect: http://www.caniuse.com/#search=preconnect

[98] prefetch: http://caniuse.com/#search=prefetch

[99] prerender: http://caniuse.com/#search=prerender

[100] preload: https://www.smashingmagazine.com/2016/02/preload-what-is-it-good-for/

[101] идёт к созданию более безопасного веба: https://security.googleblog.com/2016/09/moving-towards-more-secure-web.html

[102] HTTP/2-среду: https://http2.github.io/faq/

[103] очень хорошо поддерживается: http://caniuse.com/#search=http2

[104] сильный прирост производительности: https://www.youtube.com/watch?v=RWLzUnESylc&t=1s&list=PLNYkxOF6rcIBTs2KPy1E6tIYaWoFcG3uj&index=25

[105] новый процесс сборки: https://rmurphey.com/blog/2015/11/25/building-for-http2

[106] раздача ресурсов через HTTP/2: https://www.youtube.com/watch?v=yURLTwZ3ehk

[107] упаковка имеет смысл: http://engineering.khanacademy.org/posts/js-packaging-http2.htm

[108] IPC: https://www.chromium.org/developers/design-documents/inter-process-communication

[109] прогрессивной загрузкой CSS: https://jakearchibald.com/2016/link-in-body/

[110] настройки заголовков безопасности: https://securityheaders.io/

[111] закройте известные уязвимости: https://www.smashingmagazine.com/2016/01/eliminating-known-security-vulnerabilities-with-snyk/

[112] проверьте свой сертификат: https://www.ssllabs.com/ssltest/

[113] HTTP Strict Transport Security: https://www.owasp.org/index.php/HTTP_Strict_Transport_Security_Cheat_Sheet

[114] Content Security Policy: https://content-security-policy.com/

[115] Is TLS Fast Yet: https://istlsfastyet.com/

[116] представил Brotli: https://opensource.googleblog.com/2015/09/introducing-brotli-new-compression.html

[117] широко поддерживается: http://caniuse.com/#search=brotli

[118] получается эффективнее: https://samsaffron.com/archive/2016/06/15/the-current-state-of-brotli-compression

[119] включить Brotli даже в тех CDN, которые: http://calendar.perfplanet.com/2016/enabling-brotli-even-on-cdns-that-dont-support-it-yet/

[120] серверах OCSP stapling: https://www.digicert.com/enabling-ocsp-stapling.htm

[121] исчерпанием IPv4: https://en.wikipedia.org/wiki/IPv4_address_exhaustion

[122] достигнут: https://www.google.com/intl/en/ipv6/statistics.html#tab=ipv6-adoption&tab=ipv6-adoption

[123] обновить ваш DNS до IPv6: https://www.paessler.com/blog/2016/04/08/monitoring-news/ask-the-expert-current-status-on-ipv6

[124] Исследования показывают,: https://www.cloudflare.com/ipv6/

[125] применяли HPACK-сжатие: https://blog.cloudflare.com/hpack-the-silent-killer-feature-of-http-2/

[126] H2spec: https://github.com/summerwind/h2spec

[127] Работа HPACK: https://www.keycdn.com/blog/http2-hpack-compression/

[128] Pragmatist’s Guide to Service Workers: https://github.com/lyzadanger/pragmatist-service-worker

[129] Offline Cookbook: https://jakearchibald.com/2014/offline-cookbook/

[130] Offline Web Applications: https://www.udacity.com/course/offline-web-applications--ud899

[131] появляется поддержка: http://caniuse.com/#search=serviceworker

[132] report-uri.io: https://report-uri.io/

[133] Mixed Content Scan: https://github.com/bramus/mixed-content-scan

[134] В этом выступлении: https://www.youtube.com/watch?v=N33lYfsAsoU

[135] занимают приличную долю рынка в Азии: http://gs.statcounter.com/#mobile_browser-as-monthly-201511-201611

[136] Измерьте среднюю скорость интернета: https://www.webworldwide.io/

[137] BrowserStack: https://www.browserstack.com/

[138] SpeedCurve: https://speedcurve.com/

[139] New Relic: https://newrelic.com/browser-monitoring

[140] SpeedTracker: https://speedtracker.org/

[141] Calibre: https://calibreapp.com/

[142] PDF: http://provide.smashingmagazine.com/performance-checklist/performance-checklist-1.0.pdf

[143] Apple Pages: http://provide.smashingmagazine.com/performance-checklist/performance-checklist-1.0.pages

[144] Дэна Раблика: https://github.com/drublic/checklist

[145] Джона Яблонски: http://jonyablonski.com/designers-wpo-checklist/

[146] Источник: https://habrahabr.ru/post/320558/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best