Контрольный список производительности внешнего интерфейса на 2021 год (PDF, Apple Pages, MS Word)
Опубликовано: 2022-03-10Это руководство было любезно поддержано нашими друзьями из LogRocket, службы, которая сочетает в себе мониторинг производительности внешнего интерфейса , воспроизведение сеанса и аналитику продукта, чтобы помочь вам повысить качество обслуживания клиентов. LogRocket отслеживает ключевые показатели, в т.ч. DOM завершен, время до первого байта, задержка первого ввода, использование клиентского ЦП и памяти. Получите бесплатную пробную версию LogRocket сегодня.
Веб-производительность — хитрый зверь, не так ли? Как мы на самом деле узнаем, где мы находимся с точки зрения производительности и каковы именно наши узкие места в производительности? Это дорогой JavaScript, медленная доставка веб-шрифтов, тяжелые изображения или медленный рендеринг? Достаточно ли мы оптимизировали с помощью tree-shaking, подъема области действия, разделения кода и всех причудливых шаблонов загрузки с наблюдателем пересечений, прогрессивной гидратацией, клиентскими подсказками, HTTP/3, сервисными работниками и — о боже — пограничными работниками? И, самое главное, с чего мы вообще можем начать улучшать производительность и как нам создать культуру производительности в долгосрочной перспективе?
Раньше о производительности часто забывали . Часто отложенный до самого конца проекта, он сводился к минификации, конкатенации, оптимизации ресурсов и, возможно, нескольким тонким настройкам в файле config
сервера. Сейчас, оглядываясь назад, кажется, что все очень сильно изменилось.
Производительность — это не просто техническая проблема: она влияет на все: от доступности до удобства использования и оптимизации для поисковых систем, и при внедрении ее в рабочий процесс дизайнерские решения должны основываться на их влиянии на производительность. Производительность необходимо постоянно измерять, отслеживать и улучшать , а растущая сложность Интернета создает новые проблемы, которые усложняют отслеживание показателей, поскольку данные будут значительно различаться в зависимости от устройства, браузера, протокола, типа сети и задержки ( CDN, интернет-провайдеры, кэши, прокси-серверы, брандмауэры, балансировщики нагрузки и серверы — все это играет роль в производительности).
Итак, если бы мы создали обзор всех вещей, которые мы должны иметь в виду при повышении производительности — с самого начала проекта до финальной версии веб-сайта — как бы это выглядело? Ниже вы найдете (надеюсь, беспристрастный и объективный) контрольный список производительности внешнего интерфейса на 2021 год — обновленный обзор проблем, которые вам, возможно, придется учитывать, чтобы обеспечить быстрое время отклика, плавное взаимодействие с пользователем и бесперебойную работу ваших сайтов. истощать пропускную способность пользователя.
Оглавление
- Все на отдельных страницах
- Подготовка: планирование и показатели
Культура производительности, Core Web Vitals, профили производительности, CrUX, Lighthouse, FID, TTI, CLS, устройства. - Постановка реалистичных целей
Бюджеты производительности, цели производительности, инфраструктура RAIL, бюджеты 170 КБ/30 КБ. - Определение среды
Выбор фреймворка, базовая стоимость производительности, Webpack, зависимости, CDN, архитектура интерфейса, CSR, SSR, CSR + SSR, статический рендеринг, предварительный рендеринг, шаблон PRPL. - Оптимизация активов
Brotli, AVIF, WebP, адаптивные изображения, AV1, адаптивная загрузка мультимедиа, сжатие видео, веб-шрифты, шрифты Google. - Оптимизация сборки
Модули JavaScript, паттерн модуль/номодуль, встряхивание дерева, разделение кода, подъем объема, Webpack, дифференциальное обслуживание, веб-воркер, WebAssembly, пакеты JavaScript, React, SPA, частичная гидратация, импорт при взаимодействии, третьи стороны, кеш. - Оптимизация доставки
Отложенная загрузка, наблюдатель пересечений, отложенный рендеринг и декодирование, критический CSS, потоковая передача, подсказки ресурсов, сдвиги макета, сервисный работник. - Сеть, HTTP/2, HTTP/3
Сшивание OCSP, сертификаты EV/DV, упаковка, IPv6, QUIC, HTTP/3. - Тестирование и мониторинг
Рабочий процесс аудита, прокси-браузеры, страница 404, запросы на согласие с файлами GDPR, CSS для диагностики производительности, специальные возможности. - Быстрые победы
- Скачать контрольный список (PDF, Apple Pages, MS Word)
- Поехали!
(Вы также можете просто загрузить контрольный список в формате PDF (166 КБ) или загрузить редактируемый файл Apple Pages (275 КБ) или файл .docx (151 КБ). Всем удачной оптимизации!)
Подготовка: планирование и показатели
Микрооптимизация отлично подходит для поддержания производительности на правильном пути, но очень важно иметь в виду четко определенные цели — измеримые цели, которые будут влиять на любые решения, принимаемые на протяжении всего процесса. Есть несколько разных моделей, и те, что обсуждаются ниже, довольно самоуверенны — просто убедитесь, что вы установили свои собственные приоритеты на раннем этапе.
- Создайте культуру исполнения.
Во многих организациях фронтенд-разработчики точно знают, какие распространенные основные проблемы и какие стратегии следует использовать для их устранения. Однако до тех пор, пока не будет установленного одобрения культуры исполнения, каждое решение превратится в поле битвы между отделами, разбивая организацию на бункеры. Вам нужна поддержка заинтересованных сторон, а чтобы получить ее, вам необходимо создать тематическое исследование или доказательство концепции того, как скорость — особенно Core Web Vitals , которые мы подробно рассмотрим позже, — приносит пользу метрикам и ключевым показателям эффективности. ( KPI ), о которых они заботятся.Например, чтобы сделать производительность более ощутимой, вы можете выявить влияние на доход, показав корреляцию между коэффициентом конверсии и временем загрузки приложения, а также производительностью рендеринга. Или скорость сканирования поисковым роботом (PDF, стр. 27–50).
Без тесного взаимодействия между командами разработчиков/дизайнеров и бизнеса/маркетологов производительность не будет поддерживаться в долгосрочной перспективе. Изучите распространенные жалобы, поступающие в отдел обслуживания клиентов и отдел продаж, изучите аналитику на предмет высоких показателей отказов и падения конверсии. Узнайте, как повышение производительности может помочь решить некоторые из этих распространенных проблем. Скорректируйте аргумент в зависимости от группы заинтересованных сторон, с которой вы разговариваете.
Проводите эксперименты с производительностью и оценивайте результаты — как на мобильных устройствах, так и на компьютерах (например, с помощью Google Analytics). Это поможет вам создать индивидуальный кейс с реальными данными. Кроме того, использование данных тематических исследований и экспериментов, опубликованных в WPO Stats, поможет повысить чувствительность бизнеса к тому, почему производительность имеет значение и какое влияние она оказывает на пользовательский опыт и бизнес-показатели. Однако одного утверждения о том, что производительность имеет значение, недостаточно — вам также необходимо установить некоторые измеримые и отслеживаемые цели и соблюдать их с течением времени.
Как туда добраться? В своем выступлении на тему «Повышение производительности в долгосрочной перспективе» Эллисон Макнайт рассказывает о том, как она помогла создать культуру производительности на Etsy (слайды). Совсем недавно Тэмми Эвертс рассказала о привычках высокоэффективных команд как в малых, так и в крупных организациях.
Ведя эти разговоры в организациях, важно помнить, что точно так же, как UX — это спектр опыта, веб-производительность — это распределение. Как отметила Каролина Щур, «ожидание, что одно число сможет дать рейтинг, к которому можно стремиться, является ошибочным предположением». Следовательно, цели производительности должны быть детализированными, отслеживаемыми и осязаемыми.
- Цель: быть как минимум на 20% быстрее своего самого быстрого конкурента.
Согласно психологическим исследованиям, если вы хотите, чтобы пользователи чувствовали, что ваш сайт работает быстрее, чем сайт вашего конкурента, вам нужно быть как минимум на 20% быстрее. Изучите своих основных конкурентов, соберите показатели их эффективности на мобильных устройствах и компьютерах и установите пороговые значения, которые помогут вам опередить их. Однако, чтобы получить точные результаты и цели, сначала обязательно получите полное представление об опыте ваших пользователей, изучив свою аналитику. Затем вы можете имитировать опыт 90-го процентиля для тестирования.Чтобы получить хорошее первое впечатление о том, как работают ваши конкуренты, вы можете использовать Chrome UX Report ( CrUX , готовый набор данных RUM, вводное видео Ильи Григорика и подробное руководство Рика Вискоми) или Treo, инструмент мониторинга RUM, который работает на основе отчета Chrome UX. Данные собираются от пользователей браузера Chrome, поэтому отчеты будут специфичными для Chrome, но они дадут вам довольно подробное распределение производительности, особенно баллов Core Web Vitals, среди широкого круга ваших посетителей. Обратите внимание, что новые наборы данных CrUX публикуются во второй вторник каждого месяца .
Кроме того, вы также можете использовать:
- Инструмент сравнения отчетов Chrome UX Эдди Османи,
- Карта показателей скорости (также предоставляет оценку влияния на доход),
- Сравнение тестов реального взаимодействия с пользователем или
- SiteSpeed CI (на основе синтетического тестирования).
Примечание . Если вы используете Page Speed Insights или Page Speed Insights API (нет, это не устарело!), вы можете получать данные о производительности CrUX для конкретных страниц, а не только сводные данные. Эти данные могут быть гораздо полезнее для определения целевых показателей эффективности для таких ресурсов, как «целевая страница» или «список продуктов». И если вы используете CI для тестирования бюджетов, вам нужно убедиться, что ваша тестируемая среда соответствует CrUX, если вы использовали CrUX для установки цели ( спасибо, Патрик Минан! ).
Если вам нужна помощь, чтобы показать причины приоритета скорости, или вы хотите визуализировать падение коэффициента конверсии или увеличение показателя отказов при более низкой производительности, или, возможно, вам нужно отстаивать решение RUM в вашей организации, Сергей. Чернышев создал UX Speed Calculator, инструмент с открытым исходным кодом, который помогает вам моделировать данные и визуализировать их, чтобы донести свою точку зрения.
Иногда вы можете захотеть пойти немного глубже, объединив данные, поступающие от CrUX, с любыми другими данными, которые у вас уже есть, чтобы быстро определить, где лежат замедления, слепые зоны и неэффективность — для ваших конкурентов или для вашего проекта. В своей работе Гарри Робертс использовал электронную таблицу топографии скорости сайта, которую он использует для разбивки производительности по ключевым типам страниц и отслеживания того, как различаются ключевые показатели для них. Вы можете загрузить электронную таблицу в формате Google Sheets, Excel, документа OpenOffice или CSV.
И если вы хотите пройти весь путь, вы можете запустить аудит производительности Lighthouse на каждой странице сайта (через Lightouse Parade) с сохранением вывода в формате CSV. Это поможет вам определить, какие конкретные страницы (или типы страниц) ваших конкурентов работают хуже или лучше, и на чем вы могли бы сосредоточить свои усилия. (Для вашего собственного сайта, вероятно, лучше отправлять данные на конечную точку аналитики!).
Соберите данные, настройте электронную таблицу, сократите 20% и настройте свои цели ( бюджеты производительности ) таким образом. Теперь у вас есть что-то измеримое для тестирования. Если вы держите в уме бюджет и пытаетесь отправить только минимальную полезную нагрузку, чтобы получить быстрое время до интерактивности, то вы на разумном пути.
Нужны ресурсы для начала?
- Эдди Османи написала очень подробный отчет о том, как начать бюджетирование по результатам, как количественно оценить влияние новых функций и с чего начать, если вы превысили бюджет.
- Руководство Лары Хоган о том, как подходить к дизайну с бюджетом производительности, может дать дизайнерам полезные подсказки.
- Гарри Робертс опубликовал руководство по настройке Google Sheet для отображения влияния сторонних скриптов на производительность с помощью Request Map,
- Калькулятор бюджета производительности Джонатана Филдинга, калькулятор производительности бюджета Кэти Хемпениус и Browser Calories могут помочь в составлении бюджета (спасибо Каролине Щур за советы).
- Во многих компаниях бюджеты по результатам должны быть не желательными, а скорее прагматичными, выступая в качестве удерживающего знака, позволяющего избежать скольжения за определенную точку. В этом случае вы можете выбрать худшую точку данных за последние две недели в качестве порога и взять ее оттуда. Бюджеты производительности, Pragmatically показывает вам стратегию для достижения этого.
- Кроме того, сделайте бюджет производительности и текущую производительность видимыми , настроив информационные панели с графиками, отображающими размеры сборок. Есть много инструментов, позволяющих вам добиться этого: панель инструментов SiteSpeed.io (с открытым исходным кодом), SpeedCurve и Caliber — лишь некоторые из них, и вы можете найти больше инструментов на perf.rocks.
После того, как у вас есть бюджет, включите его в процесс сборки с помощью Webpack Performance Hints и Bundlesize, Lighthouse CI, PWMetrics или Sitespeed CI, чтобы контролировать бюджеты по запросам на вытягивание и предоставлять историю оценок в PR-комментариях.
Чтобы представить бюджеты производительности всей команде, интегрируйте бюджеты производительности в Lighthouse через Lightwallet или используйте LHCI Action для быстрой интеграции Github Actions. А если вам нужно что-то нестандартное, вы можете использовать webpagetest-charts-api, API конечных точек для построения диаграмм на основе результатов WebPagetest.
Однако осведомленность о производительности не должна исходить только от бюджетов производительности. Как и в случае с Pinterest, вы можете создать собственное правило eslint , которое запрещает импорт из файлов и каталогов, которые, как известно, сильно зависимы и могут раздуть пакет. Настройте список «безопасных» пакетов, которыми можно поделиться со всей командой.
Кроме того, подумайте о важнейших задачах клиентов, которые наиболее выгодны для вашего бизнеса. Изучите, обсудите и определите приемлемые временные пороги для критических действий и установите метки времени пользователя «Готово к UX», одобренные всей организацией. Во многих случаях пути пользователей будут касаться работы многих различных отделов, поэтому согласование с точки зрения приемлемого времени поможет поддержать или предотвратить обсуждение производительности в будущем. Убедитесь, что дополнительные затраты на дополнительные ресурсы и функции видны и понятны.
Согласуйте усилия по повышению производительности с другими техническими инициативами, начиная от новых функций создаваемого продукта и заканчивая рефакторингом и выходом на новую глобальную аудиторию. Поэтому каждый раз, когда происходит разговор о дальнейшем развитии, производительность также является частью этого разговора. Гораздо проще достичь целей производительности, когда кодовая база свежая или только что подверглась рефакторингу.
Кроме того, как предложил Патрик Минан, стоит спланировать последовательность загрузки и компромиссы в процессе проектирования. Если вы заранее расставите приоритеты, какие части являются более важными, и определите порядок, в котором они должны появляться, вы также будете знать, что может быть отложено. В идеале этот порядок также будет отражать последовательность вашего импорта CSS и JavaScript, поэтому обрабатывать их в процессе сборки будет проще. Кроме того, подумайте, каким должен быть визуальный опыт в «промежуточных» состояниях во время загрузки страницы (например, когда веб-шрифты еще не загружены).
После того, как вы создали сильную культуру производительности в своей организации, стремитесь быть на 20% быстрее, чем вы были раньше, чтобы сохранять приоритеты в такт с течением времени ( спасибо, Гай Поджарный! ). Но учитывайте различные типы и поведение ваших клиентов (которое Тобиас Бальдауф называл каденцией и когортами), а также трафик ботов и эффекты сезонности.
Планирование, планирование, планирование. Может показаться заманчивым заняться быстрой оптимизацией «низко висящих плодов» на раннем этапе — и это может быть хорошей стратегией для быстрых побед — но будет очень сложно сохранить производительность приоритетом без планирования и настройки реалистичной компании. - индивидуальные цели производительности.
- Выбирайте правильные показатели.
Не все показатели одинаково важны. Изучите, какие метрики наиболее важны для вашего приложения: обычно они будут определяться тем, насколько быстро вы сможете начать рендеринг наиболее важных пикселей вашего интерфейса и насколько быстро вы сможете обеспечить реакцию ввода для этих отображаемых пикселов. Эти знания дадут вам наилучшую цель оптимизации для текущих усилий. В конце концов, опыт определяется не событиями загрузки или временем отклика сервера, а восприятием того, насколько быстрым кажется интерфейс.Что это значит? Вместо того, чтобы сосредотачиваться на полном времени загрузки страницы (например, с помощью таймингов onLoad и DOMContentLoaded ), расставьте приоритеты загрузки страницы, как их воспринимают ваши клиенты. Это означает, что нужно сосредоточиться на немного другом наборе показателей. На самом деле выбор правильной метрики — это процесс без явных победителей.
Основываясь на исследовании Тима Кадлека и заметках Маркоса Иглесиаса в его выступлении, традиционные метрики можно сгруппировать в несколько наборов. Обычно нам нужны все из них, чтобы получить полную картину производительности, и в вашем конкретном случае некоторые из них будут более важными, чем другие.
- Метрики, основанные на количестве, измеряют количество запросов, вес и оценку производительности. Хорошо подходит для подачи сигналов тревоги и отслеживания изменений с течением времени, но не очень хорошо для понимания взаимодействия с пользователем.
- Метрики Milestone используют состояния во время жизни процесса загрузки, например Time To First Byte и Time To Interactive . Хорошо подходит для описания пользовательского опыта и мониторинга, но не очень хорошо для понимания того, что происходит между вехами.
- Показатели рендеринга позволяют оценить скорость рендеринга контента (например, время начала рендеринга , индекс скорости ). Хорошо подходит для измерения и настройки производительности рендеринга, но не так хорош для измерения того, когда появляется важный контент и с ним можно взаимодействовать.
- Пользовательские метрики измеряют конкретное пользовательское событие для пользователя, например время до первого твита в Twitter и PinnerWaitTime в Pinterest. Хорошо для точного описания пользовательского опыта, но не очень хорошо для масштабирования метрик и сравнения с конкурентами.
Для полноты картины мы обычно ищем полезные метрики среди всех этих групп. Обычно наиболее конкретными и актуальными являются:
- Время до интерактивности (TTI)
Точка, в которой макет стабилизировался , основные веб-шрифты видны, а основной поток доступен достаточно для обработки пользовательского ввода — по сути, отметка времени, когда пользователь может взаимодействовать с пользовательским интерфейсом. Ключевые показатели для понимания того, сколько времени приходится ждать пользователю, чтобы пользоваться сайтом без задержек. Борис Шапира написал подробный пост о том, как надежно измерить TTI. - Первая задержка ввода (FID) , или реакция ввода
Время с момента, когда пользователь впервые взаимодействует с вашим сайтом, до момента, когда браузер фактически может реагировать на это взаимодействие. Очень хорошо дополняет TTI, поскольку описывает недостающую часть картины: что происходит, когда пользователь фактически взаимодействует с сайтом. Предназначен только как показатель RUM. В браузере есть библиотека JavaScript для измерения FID. - Самая большая содержательная краска (LCP)
Отмечает точку на временной шкале загрузки страницы, когда, вероятно, загрузился важный контент страницы. Предполагается, что наиболее важным элементом страницы является самый большой элемент, видимый в области просмотра пользователя. Если элементы отображаются как выше, так и ниже сгиба, релевантной считается только видимая часть. - Общее время блокировки ( TBT )
Метрика, которая помогает количественно оценить серьезность того, насколько неинтерактивной является страница, до того, как она станет надежно интерактивной (то есть основной поток был свободен от каких-либо задач, выполняющихся более 50 мс ( длительных задач ) в течение как минимум 5 с). Метрика измеряет общее количество времени между первой отрисовкой и временем до взаимодействия (TTI), когда основной поток был заблокирован на достаточно долгое время, чтобы предотвратить реакцию на ввод. Поэтому неудивительно, что низкий показатель TBT является хорошим показателем хорошей производительности. (спасибо, Артем, Фил) - Совокупный сдвиг макета ( CLS )
Метрика показывает, как часто пользователи сталкиваются с неожиданными изменениями макета ( перекомпоновки ) при доступе к сайту. Он исследует нестабильные элементы и их влияние на общий опыт. Чем ниже оценка, тем лучше. - Индекс скорости
Измеряет, насколько быстро содержимое страницы визуально заполняется; чем ниже оценка, тем лучше. Оценка индекса скорости рассчитывается на основе скорости визуального прогресса , но это всего лишь расчетное значение. Он также чувствителен к размеру области просмотра, поэтому вам необходимо определить диапазон конфигураций тестирования, которые соответствуют вашей целевой аудитории. Обратите внимание, что это становится менее важным, когда LCP становится более актуальной метрикой ( спасибо, Борис, Артем! ). - Затраченное процессорное время
Метрика, показывающая, как часто и как долго блокируется основной поток, работающий над отрисовкой, рендерингом, скриптингом и загрузкой. Высокое время ЦП является явным индикатором нестабильности , т. е. когда пользователь испытывает заметную задержку между своим действием и ответом. С помощью WebPageTest вы можете выбрать «Capture Dev Tools Timeline» на вкладке «Chrome», чтобы показать разбивку основного потока, когда он работает на любом устройстве с помощью WebPageTest. - Затраты ЦП на уровне компонентов
Так же, как и время, затраченное ЦП , эта метрика, предложенная Стояном Стефановым, исследует влияние JavaScript на ЦП . Идея состоит в том, чтобы использовать количество инструкций ЦП для каждого компонента, чтобы понять их влияние на общий опыт, изолированно. Может быть реализовано с помощью Puppeteer и Chrome. - FrustrationIndex
В то время как многие метрики, представленные выше, объясняют, когда происходит конкретное событие, FrustrationIndex Тима Вереке рассматривает разрывы между метриками, а не рассматривает их по отдельности. Он рассматривает ключевые вехи, воспринимаемые конечным пользователем, такие как «Заголовок виден», «Первое содержимое видно», «Визуально готово» и «Страница выглядит готово», и вычисляет оценку, указывающую уровень разочарования при загрузке страницы. Чем больше разрыв, тем больше вероятность, что пользователь разочаруется. Потенциально хороший KPI для пользовательского опыта. Тим опубликовал подробный пост о FrustrationIndex и о том, как он работает. - Влияние веса рекламы
Если доход вашего сайта зависит от рекламы, полезно отслеживать вес кода, связанного с рекламой. Сценарий Пэдди Ганти создает два URL-адреса (один обычный и один блокирующий рекламу), запрашивает создание сравнения видео через WebPageTest и сообщает о разнице. - Показатели отклонения
Как отмечают инженеры Википедии, данные о том, насколько велики различия в ваших результатах, могут сообщить вам, насколько надежны ваши инструменты и сколько внимания вы должны уделять отклонениям и отклонениям. Большая дисперсия является индикатором корректировок, необходимых в настройке. Это также помогает понять, трудно ли надежно измерить определенные страницы, например, из-за сторонних скриптов, вызывающих значительные различия. Также может быть хорошей идеей отслеживать версию браузера, чтобы понять скачки производительности при выпуске новой версии браузера. - Пользовательские показатели
Пользовательские метрики определяются вашими бизнес-потребностями и опытом клиентов. Это требует, чтобы вы определили важные пиксели, критические скрипты, необходимый CSS и соответствующие активы и измерили, насколько быстро они доставляются пользователю. Для этого вы можете отслеживать время рендеринга героев или использовать API производительности, отмечая определенные временные метки для важных для вашего бизнеса событий. Кроме того, вы можете собирать пользовательские метрики с помощью WebPagetest, выполняя произвольный JavaScript в конце теста.
Обратите внимание, что первая значимая краска (FMP) не отображается в приведенном выше обзоре. Раньше он давал представление о том, как быстро сервер выводит какие -либо данные. Длинный FMP обычно указывал на то, что JavaScript блокирует основной поток, но также может быть связан с внутренними/серверными проблемами. Однако в последнее время эта метрика устарела, поскольку примерно в 20% случаев она оказывается неточной. Он был эффективно заменен на LCP, который является более надежным и простым в использовании. Он больше не поддерживается в Lighthouse. Дважды проверьте последние ориентированные на пользователя показатели производительности и рекомендации, чтобы убедиться, что вы находитесь на безопасной странице ( спасибо, Патрик Минан ).
У Стива Содерса есть подробное объяснение многих из этих показателей. Важно отметить, что, хотя время до взаимодействия измеряется путем проведения автоматизированных аудитов в так называемой лабораторной среде , задержка первого ввода представляет фактическое взаимодействие с пользователем, при этом реальные пользователи испытывают заметное отставание. В общем, вероятно, было бы неплохо всегда измерять и отслеживать их оба.
В зависимости от контекста вашего приложения предпочтительные метрики могут различаться: например, для пользовательского интерфейса Netflix TV более важными являются скорость отклика при вводе клавиш, использование памяти и TTI, а для Википедии более важны первые/последние визуальные изменения и показатели затраченного процессорного времени.
Примечание . И FID, и TTI не учитывают поведение прокрутки; прокрутка может происходить независимо, так как она находится вне основного потока, поэтому для многих сайтов потребления контента эти показатели могут быть гораздо менее важными ( спасибо, Патрик! ).
- Измеряйте и оптимизируйте Core Web Vitals .
Долгое время метрики производительности были чисто техническими, ориентируясь на инженерное представление о том, насколько быстро серверы отвечают и насколько быстро загружаются браузеры. Показатели менялись с годами — мы пытались найти способ зафиксировать фактическое взаимодействие с пользователем, а не тайминги сервера. В мае 2020 года Google анонсировала Core Web Vitals, набор новых показателей производительности, ориентированных на пользователя, каждый из которых представляет собой отдельный аспект взаимодействия с пользователем.Для каждого из них Google рекомендует диапазон приемлемых целей скорости. Чтобы пройти эту оценку, не менее 75 % всех просмотров страниц должны превышать диапазон «Хорошо ». Эти показатели быстро завоевали популярность, и, поскольку Core Web Vitals стали сигналами ранжирования для поиска Google в мае 2021 года ( обновление алгоритма ранжирования Page Experience ), многие компании обратили внимание на свои показатели эффективности.
Давайте разберем каждый из основных веб-показателей один за другим, а также полезные методы и инструменты для оптимизации вашего опыта с учетом этих показателей. (Стоит отметить, что вы получите более высокие баллы Core Web Vitals, если будете следовать общим советам из этой статьи.)
- Самая большая содержательная отрисовка ( LCP ) < 2,5 сек.
Измеряет загрузку страницы и сообщает о времени рендеринга самого большого изображения или текстового блока , видимого в области просмотра. Следовательно, на LCP влияет все, что откладывает рендеринг важной информации — будь то медленное время отклика сервера, блокировка CSS, работающий JavaScript (собственный или сторонний), загрузка веб-шрифтов, дорогостоящие операции рендеринга или рисования, ленивый загруженные изображения, каркасные экраны или рендеринг на стороне клиента.
Для удобства LCP должен выполняться в течение 2,5 с после первой загрузки страницы. Это означает, что нам нужно отобразить первую видимую часть страницы как можно раньше. Это потребует адаптированного критического CSS для каждого шаблона, оркестровки<head>
-order и предварительной выборки критически важных ресурсов (мы рассмотрим их позже).Основной причиной низкой оценки LCP обычно являются изображения. Чтобы доставить LCP менее чем за 2,5 с на Fast 3G — размещенном на хорошо оптимизированном сервере, полностью статичном без рендеринга на стороне клиента и с изображением, поступающим из выделенной сети доставки изображений — это означает, что максимальный теоретический размер изображения составляет всего около 144 КБ . Вот почему так важны адаптивные изображения, а также ранняя предварительная загрузка важных изображений (с
preload
).Небольшой совет : чтобы узнать, что считается LCP на странице, в DevTools вы можете навести указатель мыши на значок LCP в разделе «Время» на панели производительности ( спасибо, Тим Кадлек !).
- Задержка первого входа ( FID ) < 100 мс.
Измеряет скорость отклика пользовательского интерфейса, т. е . как долго браузер был занят другими задачами, прежде чем он смог отреагировать на дискретное событие пользовательского ввода, например касание или щелчок. Он предназначен для отслеживания задержек, возникающих из-за занятости основного потока, особенно во время загрузки страницы.
Цель состоит в том, чтобы оставаться в пределах 50–100 мс для каждого взаимодействия. Чтобы достичь этого, нам нужно идентифицировать длинные задачи (блокирует основной поток на> 50 мс) и разбить их, разбить код на несколько частей, сократить время выполнения JavaScript, оптимизировать выборку данных, отложить выполнение скриптов сторонних разработчиков. , переместите JavaScript в фоновый поток с помощью веб-воркеров и используйте прогрессивную гидратацию, чтобы снизить затраты на регидратацию в SPA.Небольшой совет : как правило, надежная стратегия для получения более высокой оценки FID заключается в том, чтобы свести к минимуму работу в основном потоке , разбивая большие пакеты на более мелкие и предоставляя то, что нужно пользователю, когда ему это нужно, чтобы взаимодействие с пользователем не задерживалось. . Подробнее об этом мы расскажем ниже.
- Совокупный сдвиг макета ( CLS ) <0,1.
Измеряет визуальную стабильность пользовательского интерфейса для обеспечения плавного и естественного взаимодействия, т. е. общую сумму всех индивидуальных оценок смещения макета для каждого неожиданного изменения макета, которое происходит в течение срока службы страницы. Индивидуальное смещение макета происходит каждый раз, когда элемент, который уже был виден, меняет свое положение на странице. Он оценивается в зависимости от размера контента и расстояния, на которое он был перемещен.
Таким образом, каждый раз, когда происходит изменение — например, когда запасные шрифты и веб-шрифты имеют разные метрики шрифта, или реклама, встраивание или iframe появляются с опозданием, или размеры изображения/видео не зарезервированы, или поздний CSS принудительно перекрашивает, или изменения вводятся поздний JavaScript — это влияет на оценку CLS. Рекомендуемое значение для хорошего опыта — CLS < 0,1.
Стоит отметить, что Core Web Vitals должны развиваться с течением времени с предсказуемым годовым циклом . В течение первого года обновления мы можем ожидать, что First Contentful Paint будет повышен до Core Web Vitals, снижен порог FID и улучшена поддержка одностраничных приложений. Мы также можем увидеть, как ответы на вводимые пользователем данные после нагрузки приобретают все больший вес, наряду с соображениями безопасности, конфиденциальности и доступности (!).
Что касается Core Web Vitals, существует множество полезных ресурсов и статей, на которые стоит обратить внимание:
- Web Vitals Leaderboard позволяет сравнивать свои результаты с конкурентами на мобильных устройствах, планшетах, настольных компьютерах, а также в сетях 3G и 4G.
- Core SERP Vitals, расширение Chrome, которое показывает Core Web Vitals из CrUX в результатах поиска Google.
- Генератор Layout Shift GIF, который визуализирует CLS с помощью простого GIF (также доступен из командной строки).
- web-vitals может собирать и отправлять Core Web Vitals в Google Analytics, Диспетчер тегов Google или любую другую конечную точку аналитики.
- Анализ Web Vitals с помощью WebPageTest, в котором Патрик Минан исследует, как WebPageTest предоставляет данные о Core Web Vitals.
- Оптимизация с помощью Core Web Vitals, 50-минутное видео с Эдди Османи, в котором он рассказывает, как улучшить Core Web Vitals на примере электронной коммерции.
- Cumulative Layout Shift in Practice и Cumulative Layout Shift in the Real World — подробные статьи Ника Янсмы, которые охватывают почти все, что касается CLS, и того, как она коррелирует с ключевыми показателями, такими как показатель отказов, время сеанса или клики Rage.
- What Forces Reflow, с обзором свойств или методов, при запросе/вызове в JavaScript, который заставит браузер синхронно вычислить стиль и макет.
- Триггеры CSS показывают, какие свойства CSS запускают Layout, Paint и Composite.
- Исправление нестабильности макета — это пошаговое руководство по использованию WebPageTest для выявления и устранения проблем нестабильности макета.
- Cumulative Layout Shift, The Layout Instability Metric, еще одно очень подробное руководство Бориса Шапира по CLS, как оно рассчитывается, как его измерять и как его оптимизировать.
- How To Improve Core Web Vitals — подробное руководство Саймона Херна по каждой метрике (включая другие Web Vitals, такие как FCP, TTI, TBT), когда они возникают и как они измеряются.
Итак, являются ли Core Web Vitals окончательными показателями ? Не совсем. Они действительно представлены в большинстве решений и платформ RUM, включая Cloudflare, Treo, SpeedCurve, Calibre, WebPageTest (уже в диафильме), Newrelic, Shopify, Next.js, во всех инструментах Google (PageSpeed Insights, Lighthouse + CI, Search консоли и др.) и многие другие.
Однако, как объясняет Кэти Силор-Миллер, некоторые из основных проблем с Core Web Vitals заключаются в отсутствии кросс-браузерной поддержки, мы на самом деле не измеряем полный жизненный цикл взаимодействия с пользователем, а также трудно сопоставить изменения в FID и CLS с бизнес-результатами.
Поскольку мы должны ожидать, что Core Web Vitals будет развиваться, кажется вполне разумным всегда комбинировать Web Vitals с вашими индивидуальными показателями, чтобы лучше понять, где вы находитесь с точки зрения производительности.
- Самая большая содержательная отрисовка ( LCP ) < 2,5 сек.
- Соберите данные об устройстве, представляющем вашу аудиторию.
Чтобы собрать точные данные, нам нужно тщательно выбирать устройства для тестирования. В большинстве компаний это означает изучение аналитики и создание профилей пользователей на основе наиболее распространенных типов устройств. Однако зачастую аналитика сама по себе не дает полной картины. Значительная часть целевой аудитории может покинуть сайт (и не вернуться обратно) только потому, что их работа слишком медленная, и их устройства вряд ли будут отображаться как самые популярные устройства в аналитике по этой причине. Поэтому хорошей идеей может быть дополнительное исследование распространенных устройств в вашей целевой группе.По данным IDC, в 2020 году во всем мире 84,8% всех поставляемых мобильных телефонов являются устройствами Android. Средний потребитель обновляет свой телефон каждые 2 года, а в США цикл замены телефона составляет 33 месяца. В среднем самые продаваемые телефоны по всему миру будут стоить менее 200 долларов.
Таким образом, репрезентативным устройством является устройство Android, которому не менее 24 месяцев , стоимостью 200 долларов или меньше, работающее на медленном 3G, 400 мс RTT и 400 кбит / с, просто чтобы быть немного более пессимистичным. Конечно, это может сильно отличаться для вашей компании, но это достаточно близкое приближение к большинству клиентов. На самом деле, было бы неплохо изучить текущие бестселлеры Amazon для вашего целевого рынка. ( Спасибо Tim Kadlec, Henri Helvetica и Alex Russell за подсказки! ).
Какие тестовые устройства выбрать тогда? Те, которые хорошо вписываются в профиль, описанный выше. Это хороший вариант, чтобы выбрать немного более старый Moto G4/G5 Plus, устройство Samsung среднего класса (Galaxy A50, S8), хорошее устройство среднего уровня, такое как Nexus 5X, Xiaomi Mi A3 или Xiaomi Redmi Note. 7 и медленное устройство, такое как Alcatel 1X или Cubot X19, возможно, в открытой лаборатории устройств. Для тестирования на более медленных устройствах с терморегулированием вы также можете приобрести Nexus 4, который стоит всего около 100 долларов.
Кроме того, проверьте наборы микросхем, используемые в каждом устройстве, и не переоценивайте один набор микросхем : нескольких поколений Snapdragon и Apple, а также бюджетных Rockchip, Mediatek будет достаточно (спасибо, Патрик!) .
Если у вас нет устройства под рукой, эмулируйте мобильный опыт на настольном компьютере, протестировав сеть 3G с дросселированием (например, 300 мс RTT, 1,6 Мбит/с на вход, 0,8 Мбит/с) с дросселированием ЦП (замедление в 5 раз). Со временем переключитесь на обычный 3G, медленный 4G (например, 170 мс RTT, 9 Мбит/с входящий, 9 Мбит/с исходящий) и Wi-Fi. Чтобы сделать влияние на производительность более заметным, вы можете даже ввести 2G по вторникам или настроить регулируемую сеть 3G/4G в своем офисе для более быстрого тестирования.
Имейте в виду, что на мобильном устройстве следует ожидать замедления в 4–5 раз по сравнению с настольными компьютерами. Мобильные устройства имеют разные графические процессоры, процессоры, память и разные характеристики батареи. Вот почему важно иметь хороший профиль среднего устройства и всегда проводить тестирование на таком устройстве.
- Инструменты синтетического тестирования собирают лабораторные данные в воспроизводимой среде с предопределенными настройками устройства и сети (например, Lighthouse , Caliber , WebPageTest ) и
- Инструменты Real User Monitoring ( RUM ) постоянно оценивают взаимодействие пользователей и собирают полевые данные (например, SpeedCurve , New Relic — эти инструменты также обеспечивают синтетическое тестирование).
- используйте Lighthouse CI для отслеживания показателей Lighthouse с течением времени (это весьма впечатляет),
- запустите Lighthouse в GitHub Actions, чтобы получать отчет Lighthouse вместе с каждым PR,
- запустить аудит производительности Lighthouse на каждой странице сайта (через Lightouse Parade) с сохранением результатов в формате CSV,
- используйте калькулятор Lighthouse Scores Calculator и метрические веса Lighthouse, если вам нужно углубиться в детали.
- Lighthouse также доступен для Firefox, но внутри он использует API PageSpeed Insights и генерирует отчет на основе безголового пользовательского агента Chrome 79.
К счастью, есть много отличных вариантов, которые помогут вам автоматизировать сбор данных и измерить, как ваш сайт работает с течением времени в соответствии с этими показателями. Имейте в виду, что хорошая картина производительности охватывает набор показателей производительности, лабораторных данных и полевых данных:
Первый особенно полезен во время разработки , так как помогает выявлять, изолировать и устранять проблемы с производительностью во время работы над продуктом. Последнее полезно для долгосрочного обслуживания , поскольку оно поможет вам понять ваши узкие места в производительности, когда они происходят в реальном времени — когда пользователи фактически заходят на сайт.
Используя встроенные API-интерфейсы RUM, такие как Navigation Timing, Resource Timing, Paint Timing, Long Tasks и т. д., инструменты синтетического тестирования и RUM вместе дают полную картину производительности вашего приложения. Вы можете использовать Calibre, Treo, SpeedCurve, mPulse и Boomerang, Sitespeed.io, которые отлично подходят для мониторинга производительности. Кроме того, с заголовком Server Timing вы можете даже отслеживать производительность серверной и клиентской части в одном месте.
Примечание . Всегда безопаснее выбирать дроссели сетевого уровня, внешние по отношению к браузеру, поскольку, например, у DevTools есть проблемы с взаимодействием с HTTP/2 push из-за того, как он реализован ( спасибо, Йоав, Патрик !). Для Mac OS мы можем использовать Network Link Conditioner, для Windows — Windows Traffic Shaper, для Linux — netem, а для FreeBSD — dummynet.
Поскольку, скорее всего, вы будете проводить тестирование в Lighthouse, имейте в виду, что вы можете:
- Настройте «чистый» и «клиентский» профили для тестирования.
При выполнении тестов в инструментах пассивного мониторинга распространенной стратегией является отключение антивируса и фоновых задач ЦП, удаление фоновой передачи полосы пропускания и тестирование с чистым профилем пользователя без расширений браузера, чтобы избежать искажения результатов (в Firefox и в Chrome).Тем не менее, также рекомендуется изучить, какие расширения браузера часто используют ваши клиенты, а также протестировать их с помощью специальных профилей «клиентов» . На самом деле, некоторые расширения могут оказывать значительное влияние на производительность вашего приложения (отчет о производительности расширений Chrome за 2020 г.), и если ваши пользователи часто их используют, вы можете заранее учесть это. Следовательно, одни только «чистые» результаты профиля являются чрезмерно оптимистичными и могут быть разрушены в реальных сценариях.
- Поделитесь целями производительности с вашими коллегами.
Убедитесь, что цели эффективности знакомы каждому члену вашей команды, чтобы избежать недоразумений в будущем. Каждое решение — будь то дизайн, маркетинг или что-то промежуточное — влияет на производительность , а распределение ответственности и ответственности между всей командой упростит принятие решений, ориентированных на производительность, в дальнейшем. Сопоставьте проектные решения с бюджетом производительности и приоритетами, определенными на раннем этапе.
Постановка реалистичных целей
- Время отклика 100 миллисекунд, 60 кадров в секунду.
Чтобы взаимодействие было плавным, у интерфейса есть 100 мс для ответа на ввод пользователя. Еще немного, и пользователь воспринимает приложение как тормозящее. RAIL, модель производительности, ориентированная на пользователя, дает вам здоровые цели : чтобы обеспечить отклик <100 миллисекунд, страница должна возвращать управление обратно основному потоку не позднее, чем через каждые <50 миллисекунд. Расчетная задержка ввода сообщает нам, достигаем ли мы этого порога, и в идеале она должна быть ниже 50 мс. Для точек высокого давления, таких как анимация, лучше ничего не делать там, где вы можете, и абсолютный минимум там, где вы не можете.Кроме того, каждый кадр анимации должен быть завершен менее чем за 16 миллисекунд, таким образом достигнув 60 кадров в секунду (1 секунда ÷ 60 = 16,6 миллисекунды) — желательно менее 10 миллисекунд. Поскольку браузеру нужно время, чтобы отобразить новый кадр на экране, ваш код должен завершить выполнение до достижения отметки в 16,6 миллисекунды. Мы начинаем вести разговоры о 120 кадрах в секунду (например, экраны iPad Pro работают на частоте 120 Гц), и Surma рассмотрела некоторые решения для повышения производительности рендеринга для 120 кадров в секунду, но, вероятно, это пока не наша цель.
Будьте пессимистичны в ожиданиях производительности, но будьте оптимистичны в дизайне интерфейса и разумно используйте время простоя (отметьте idlize, idle-until-urgent и response-idle). Очевидно, что эти цели относятся к производительности во время выполнения, а не к производительности при загрузке.
- FID < 100 мс, LCP < 2,5 с, TTI < 5 с в 3G, бюджет критического размера файла < 170 КБ (сжатый gzip).
Хотя это может быть очень сложно достичь, хорошей конечной целью будет время до взаимодействия менее 5 с, а для повторных посещений стремитесь к менее 2 с (достижимо только с сервисным работником). Стремитесь к наибольшей отрисовке содержимого менее чем за 2,5 с и минимизируйте общее время блокировки и кумулятивное смещение макета . Приемлемая задержка первого входа составляет менее 100–70 мс. Как упоминалось выше, мы рассматриваем в качестве базового уровня Android-телефон стоимостью 200 долларов (например, Moto G4) в медленной сети 3G, эмулируемой при RTT 400 мс и скорости передачи 400 кбит/с.У нас есть два основных ограничения, которые эффективно формируют разумную цель для быстрой доставки контента в Интернете. С одной стороны, у нас есть ограничения доставки по сети из-за медленного старта TCP. Первые 14 КБ HTML — 10 TCP-пакетов, каждый по 1460 байт, что составляет около 14,25 КБ, хотя это и не следует понимать буквально — это наиболее важный фрагмент полезной нагрузки и единственная часть бюджета, которая может быть доставлена за первую передачу туда и обратно ( это все, что вы получаете за 1 секунду при RTT 400 мс из-за времени пробуждения мобильных устройств).
( Примечание : поскольку TCP, как правило, значительно недоиспользует сетевое подключение, Google разработал TCP узкое место и RRT ( BBR ), алгоритм управления потоком TCP с контролем задержки. Разработанный для современной сети, он реагирует на фактическую перегрузку, вместо потери пакетов, как это делает TCP, он значительно быстрее, с более высокой пропускной способностью и меньшей задержкой — и алгоритм работает по-другому ( спасибо, Виктор, Барри! )
С другой стороны, у нас есть аппаратные ограничения на память и процессор из-за времени парсинга и выполнения JavaScript (мы поговорим о них подробнее позже). Чтобы достичь целей, указанных в первом абзаце, мы должны учитывать критический бюджет размера файла для JavaScript. Мнения о том, каким должен быть этот бюджет, расходятся (и это сильно зависит от характера вашего проекта), но бюджет в 170 КБ JavaScript, уже сжатый gzip, потребует до 1 с для анализа и компиляции на телефоне среднего класса. Если предположить, что 170 КБ расширяются до 3-кратного размера при распаковке (0,7 МБ), это уже может быть похоронным звоном «приличного» пользовательского опыта на Moto G4 / G5 Plus.
Что касается веб-сайта Википедии, то в 2020 году во всем мире выполнение кода для пользователей Википедии ускорилось на 19%. Таким образом, если ваши годовые показатели веб-производительности остаются стабильными, это обычно предупреждающий знак, поскольку вы на самом деле регрессируете , поскольку среда продолжает улучшаться (подробности в сообщении в блоге Жиля Дюбюка).
Если вы хотите ориентироваться на растущие рынки, такие как Юго-Восточная Азия, Африка или Индия, вам придется изучить совсем другой набор ограничений. Эдди Османи охватывает основные ограничения функциональных телефонов, такие как небольшое количество недорогих высококачественных устройств, недоступность высококачественных сетей и дорогие мобильные данные, а также бюджет PRPL-30 и рекомендации по разработке для этих сред.
Фактически, Алекс Рассел из Google рекомендует ориентироваться на 130–170 КБ в сжатом виде в качестве разумной верхней границы. В реальных сценариях большинство продуктов даже близко не стоят: средний размер пакета сегодня составляет около 452 КБ, что на 53,6% больше, чем в начале 2015 года. На мобильном устройстве среднего класса это составляет 12–20 секунд для времени . -To-Interactive .
Мы также могли бы выйти за рамки бюджета размера пакета. Например, мы могли бы установить бюджеты производительности на основе активности основного потока браузера, т. е. времени отрисовки перед началом рендеринга или отследить загрузку процессора внешнего интерфейса. Такие инструменты, как Calibre, SpeedCurve и Bundlesize, помогут вам контролировать бюджет и могут быть интегрированы в процесс сборки.
Наконец, бюджет производительности, вероятно , не должен быть фиксированным значением . В зависимости от сетевого подключения бюджеты производительности должны адаптироваться, но полезная нагрузка при более медленном соединении гораздо более «дорогая», независимо от того, как они используются.
Примечание . Может показаться странным устанавливать такие жесткие бюджеты во времена широкого распространения HTTP/2, грядущих 5G и HTTP/3, быстро развивающихся мобильных телефонов и процветающих SPA. Тем не менее, они звучат разумно, когда мы имеем дело с непредсказуемым характером сети и оборудования, включая все, от перегруженных сетей до медленно развивающейся инфраструктуры, ограничений данных, прокси-браузеров, режима сохранения данных и скрытой платы за роуминг.
Определение среды
- Выберите и настройте инструменты сборки.
Не обращайте слишком много внимания на то, что в наши дни считается крутым. Придерживайтесь своей среды для сборки, будь то Grunt, Gulp, Webpack, Parcel или комбинация инструментов. Пока вы получаете нужные результаты и у вас нет проблем с поддержанием процесса сборки, у вас все в порядке.Среди инструментов сборки Rollup продолжает набирать обороты, как и Snowpack, но Webpack, кажется, является наиболее признанным, с буквально сотнями доступных плагинов для оптимизации размера ваших сборок. Следите за дорожной картой Webpack 2021.
Одной из наиболее примечательных стратегий, появившихся в последнее время, является дробное разбиение на фрагменты с помощью Webpack в Next.js и Gatsby для минимизации дублирования кода. По умолчанию модули, которые не являются общими в каждой точке входа, могут быть запрошены для маршрутов, которые их не используют. В конечном итоге это становится накладными расходами, поскольку загружается больше кода, чем необходимо. Благодаря гранулированному фрагментированию в Next.js мы можем использовать файл манифеста сборки на стороне сервера, чтобы определить, какие выходные фрагменты используются разными точками входа.
С помощью SplitChunksPlugin несколько разделенных фрагментов создаются в зависимости от ряда условий, чтобы предотвратить выборку дублированного кода по нескольким маршрутам. Это улучшает время загрузки страницы и кэширование во время навигации. Поставляется в Next.js 9.2 и в Gatsby v2.20.7.
Однако начать работу с Webpack может быть сложно. Итак, если вы хотите погрузиться в Webpack, есть несколько отличных ресурсов:
- Документация по Webpack — очевидно — является хорошей отправной точкой, как и Webpack — The Confusing Bits от Raja Rao и Annotated Webpack Config от Andrew Welch.
- У Шона Ларкина есть бесплатный курс по Webpack: The Core Concepts, а Джеффри Уэй выпустил фантастический бесплатный курс по Webpack для всех. Оба они являются отличным введением для погружения в Webpack.
- Webpack Fundamentals — это очень подробный 4-часовой курс с Шоном Ларкиным, выпущенный FrontendMasters.
- Примеры Webpack содержат сотни готовых к использованию конфигураций Webpack, классифицированных по темам и целям. Бонус: есть также конфигуратор конфигурации Webpack, который генерирует базовый файл конфигурации.
- awesome-webpack — это список полезных ресурсов, библиотек и инструментов Webpack, включая статьи, видео, курсы, книги и примеры для Angular, React и проектов, не зависящих от фреймворка.
- Путь к быстрой сборке производственных активов с помощью Webpack — это тематическое исследование Etsy о том, как команда перешла от использования системы сборки JavaScript на основе RequireJS к использованию Webpack и как они оптимизировали свои сборки, управляя более чем 13 200 активами в среднем за 4 минуты .
- Советы по производительности Webpack — золотая ветка Ивана Акулова, содержащая множество советов, ориентированных на производительность, в том числе те, которые специально ориентированы на Webpack.
- awesome-webpack-perf — это золотой репозиторий GitHub с полезными инструментами и плагинами Webpack для повышения производительности. Также поддерживается Иваном Акуловым.
- Используйте прогрессивное улучшение по умолчанию.
Тем не менее, по прошествии стольких лет, сохранение прогрессивного улучшения в качестве руководящего принципа вашей интерфейсной архитектуры и развертывания является беспроигрышным вариантом. Сначала спроектируйте и создайте основной интерфейс, а затем улучшите его с помощью расширенных функций для совместимых браузеров, создавая устойчивые интерфейсы. Если ваш веб-сайт работает быстро на медленной машине с плохим экраном в плохом браузере в неоптимальной сети, то он будет работать быстрее только на быстрой машине с хорошим браузером в приличной сети.На самом деле, с адаптивным обслуживанием модулей мы, кажется, выводим прогрессивное улучшение на новый уровень, предоставляя «упрощенные» базовые возможности для недорогих устройств и добавляя более сложные функции для устройств высокого класса. Прогрессивное улучшение вряд ли исчезнет в ближайшее время.
- Выберите сильный базовый уровень производительности.
С таким количеством неизвестных факторов, влияющих на загрузку — сеть, тепловое регулирование, удаление кеша, сторонние сценарии, шаблоны блокировки синтаксического анализатора, дисковый ввод-вывод, задержка IPC, установленные расширения, антивирусное программное обеспечение и брандмауэры, фоновые задачи ЦП, ограничения оборудования и памяти, различия в кэшировании L2/L3, RTTS — JavaScript имеет самую большую стоимость опыта, рядом с веб-шрифтами, блокирующими рендеринг по умолчанию, и изображениями, часто потребляющими слишком много памяти. Поскольку узкие места в производительности переходят от сервера к клиенту, мы, как разработчики, должны рассмотреть все эти неизвестные гораздо подробнее.С бюджетом в 170 КБ, который уже содержит критический путь HTML/CSS/JavaScript, маршрутизатор, управление состоянием, утилиты, фреймворк и логику приложения, мы должны тщательно изучить стоимость передачи по сети, время синтаксического анализа/компиляции и стоимость времени выполнения. рамки по нашему выбору. К счастью, за последние несколько лет мы наблюдаем значительный прогресс в том, насколько быстро браузеры могут анализировать и компилировать скрипты. Тем не менее, выполнение JavaScript по-прежнему является основным узким местом, поэтому пристальное внимание к времени выполнения скрипта и сети может иметь большое значение.
Тим Кадлек провел фантастическое исследование производительности современных фреймворков и резюмировал их в статье «Фреймворки JavaScript имеют свою цену». Мы часто говорим о влиянии автономных фреймворков, но, как отмечает Тим, на практике нередко используется несколько фреймворков . Возможно, это старая версия jQuery, которая постепенно переносится на современный фреймворк, а также несколько устаревших приложений, использующих более старую версию Angular. Поэтому более разумно изучить совокупную стоимость байтов JavaScript и время выполнения ЦП, которые могут легко сделать пользовательский опыт практически непригодным для использования даже на устройствах высокого класса.
Как правило, современные фреймворки не отдают приоритет менее мощным устройствам , поэтому производительность на телефоне и на настольном компьютере часто сильно различается. Согласно исследованиям, сайты с React или Angular тратят на ЦП больше времени, чем другие (что, конечно, не обязательно означает, что React требует больше ресурсов ЦП, чем Vue.js).
По словам Тима, очевидно одно: «если вы используете фреймворк для создания своего сайта, вы идете на компромисс с точки зрения начальной производительности — даже в лучшем из сценариев».
- Оцените фреймворки и зависимости.
Теперь не каждому проекту нужен фреймворк, и не каждая страница одностраничного приложения должна загружать фреймворк. В случае с Netflix «удаление React, нескольких библиотек и соответствующего кода приложения со стороны клиента уменьшило общий объем JavaScript более чем на 200 КБ, что привело к сокращению времени до интерактивности Netflix более чем на 50% для домашней страницы, на которой не выполнен вход. ." Затем команда использовала время, проведенное пользователями на целевой странице, для предварительной выборки React для последующих страниц, на которые, скорее всего, попадут пользователи (подробности читайте далее).Так что, если вы вообще удалите существующую структуру на критических страницах? С Gatsby вы можете проверить gatsby-plugin-no-javascript, который удаляет все файлы JavaScript, созданные Gatsby, из статических файлов HTML. В Vercel вы также можете разрешить отключение исполняемого JavaScript для определенных страниц (экспериментально).
После того, как фреймворк выбран, мы будем использовать его как минимум несколько лет, поэтому, если нам нужно его использовать, мы должны убедиться, что наш выбор обоснован и хорошо продуман — и это особенно касается ключевых показателей производительности, которые мы заботиться о.
Данные показывают, что по умолчанию фреймворки довольно дороги: 58,6% страниц React содержат более 1 МБ JavaScript, а 36% загрузок страниц Vue.js имеют первую отрисовку содержимого менее 1,5 с. Согласно исследованию Анкура Сетхи, «ваше приложение React никогда не будет загружаться быстрее, чем за 1,1 секунды на среднем телефоне в Индии, независимо от того, насколько вы его оптимизируете. Для загрузки вашего приложения Angular всегда требуется не менее 2,7 секунды». пользователям вашего приложения Vue нужно будет подождать не менее 1 секунды, прежде чем они смогут начать его использовать». Возможно, вы в любом случае не ориентируетесь на Индию как на основной рынок, но пользователи, заходящие на ваш сайт с неоптимальными сетевыми условиями, будут иметь сопоставимый опыт.
Конечно , можно делать SPA быстро, но они не быстры из коробки, поэтому нам нужно учитывать время и усилия, необходимые для их быстрого создания и поддержания . Вероятно, будет проще выбрать облегченную базовую стоимость производительности на раннем этапе.
Итак, как мы выбираем фреймворк ? Прежде чем выбирать вариант, рекомендуется учитывать как минимум общую стоимость размера + начальное время выполнения; легкие варианты, такие как Preact, Inferno, Vue, Svelte, Alpine или Polymer, могут отлично справиться с работой. Размер вашего базового плана будет определять ограничения для кода вашего приложения.
Как отмечает Себ Маркбейдж, хороший способ измерить начальные затраты для фреймворков — сначала отобразить представление, затем удалить его, а затем снова отрендерить, поскольку это может сказать вам, как масштабируется фреймворк. Первый рендер имеет тенденцию разогревать кучу лениво скомпилированного кода, что может принести пользу более крупному дереву при его масштабировании. Второй рендеринг в основном представляет собой эмуляцию того, как повторное использование кода на странице влияет на характеристики производительности по мере усложнения страницы.
Вы можете даже оценить своих кандидатов (или любую библиотеку JavaScript в целом) по 12-балльной системе оценки Саши Грейфа, изучив функции, доступность, стабильность, производительность, экосистему пакетов , сообщество, кривую обучения, документацию, инструменты, послужной список. , команда, совместимость, безопасность например.
Вы также можете полагаться на данные, собранные в Интернете за более длительный период времени. Например, Perf Track отслеживает производительность платформы в масштабе, показывая агрегированные по источнику баллы Core Web Vitals для веб-сайтов, созданных на Angular, React, Vue, Polymer, Preact, Ember, Svelte и AMP. Вы даже можете указать и сравнить веб-сайты, созданные с помощью Gatsby, Next.js или Create React App, а также веб-сайты, созданные с помощью Nuxt.js (Vue) или Sapper (Svelte).
Хорошей отправной точкой является выбор хорошего стека по умолчанию для вашего приложения. Gatsby (React), Next.js (React), Vuepress (Vue), Preact CLI и PWA Starter Kit обеспечивают разумные значения по умолчанию для быстрой загрузки из коробки на среднее мобильное оборудование. Также ознакомьтесь с руководством по производительности для React и Angular, относящимся к фреймворку web.dev ( спасибо, Филипп! ).
И, возможно, вы могли бы применить немного более свежий подход к созданию одностраничных приложений в целом — Turbolinks, библиотеку JavaScript размером 15 КБ, которая использует HTML вместо JSON для отображения представлений. Поэтому, когда вы переходите по ссылке, Turbolinks автоматически извлекает страницу, заменяет ее
<body>
и объединяет ее<head>
, и все это без затрат на полную загрузку страницы. Вы можете проверить краткие подробности и полную документацию о стеке (Hotwire).
- Рендеринг на стороне клиента или рендеринг на стороне сервера? Обе!
Это довольно горячий разговор. Окончательным подходом было бы настроить своего рода прогрессивную загрузку: использовать рендеринг на стороне сервера, чтобы получить быструю первую контекстную отрисовку, но также включить минимально необходимый JavaScript, чтобы время до интерактивности оставалось близким к первой контентной отрисовке. Если JavaScript появляется слишком поздно после FCP, браузер блокирует основной поток при анализе, компиляции и выполнении поздно обнаруженного JavaScript, тем самым ограничивая интерактивность сайта или приложения.Чтобы этого избежать, всегда разбивайте выполнение функций на отдельные асинхронные задачи и по возможности используйте
requestIdleCallback
. Рассмотрите ленивую загрузку частей пользовательского интерфейса с помощью поддержки динамическогоimport()
WebPack, избегая затрат на загрузку, синтаксический анализ и компиляцию до тех пор, пока они действительно не понадобятся пользователям ( спасибо, Адди! ).Как упоминалось выше, время до интерактивности (TTI) сообщает нам время между навигацией и интерактивностью. В деталях метрика определяется путем просмотра первого пятисекундного окна после рендеринга начального контента, в котором ни одна задача JavaScript не занимает более 50 мс ( длительные задачи ). Если возникает задача более 50 мс, поиск пятисекундного окна начинается заново. В результате браузер сначала предположит, что он достиг Interactive , просто для того, чтобы переключиться на Frozen , чтобы в конечном итоге переключиться обратно на Interactive .
Как только мы достигли Interactive , мы можем — либо по требованию, либо, когда позволяет время — загружать второстепенные части приложения. К сожалению, как заметил Пол Льюис, фреймворки обычно не имеют простой концепции приоритета, которую можно было бы донести до разработчиков, и, следовательно, прогрессивную загрузку нелегко реализовать с большинством библиотек и фреймворков.
Тем не менее, мы добираемся туда. В наши дни есть несколько вариантов, которые мы можем изучить, и Хусейн Джирдех и Джейсон Миллер предоставили отличный обзор этих вариантов в своем докладе о рендеринге в Интернете и в статье Джейсона и Эдди о современных интерфейсных архитектурах. Обзор ниже основан на их звездной работе.
- Полный рендеринг на стороне сервера (SSR)
В классическом SSR, таком как WordPress, все запросы обрабатываются исключительно на сервере. Запрошенный контент возвращается в виде готовой HTML-страницы, и браузеры могут сразу ее отображать. Следовательно, SSR-приложения не могут использовать, например, DOM API. Разрыв между First Contentful Paint и Time to Interactive обычно невелик, и страница может отображаться сразу же, как HTML передается в браузер.Это позволяет избежать дополнительных циклов получения данных и шаблонов на клиенте, поскольку они обрабатываются до того, как браузер получит ответ. Тем не менее, мы получаем больше времени на обдумывание сервером и, следовательно, времени до первого байта, и мы не используем адаптивные и богатые функции современных приложений.
- Статическая визуализация
Мы создаем продукт как одностраничное приложение, но все страницы предварительно визуализируются в статический HTML с минимальным JavaScript в качестве шага сборки. Это означает, что при статическом рендеринге мы заранее создаем отдельные HTML-файлы для каждого возможного URL -адреса, что не многие приложения могут себе позволить. Но поскольку HTML-код для страницы не нужно генерировать на лету, мы можем добиться неизменно быстрого времени до первого байта. Таким образом, мы можем быстро отобразить целевую страницу, а затем выполнить предварительную выборку SPA-фреймворка для последующих страниц. Netflix применил этот подход, снизив загрузку и время до взаимодействия на 50%. - Рендеринг на стороне сервера с (ре)гидратацией (универсальный рендеринг, SSR + CSR)
Мы можем попытаться использовать лучшее из обоих подходов — SSR и CSR. С добавлением гидратации HTML-страница, возвращаемая с сервера, также содержит сценарий, который загружает полноценное клиентское приложение. В идеале добиться быстрой первой отрисовки содержимого (например, SSR), а затем продолжить рендеринг с (ре)гидратацией. К сожалению, это бывает редко. Чаще страница выглядит готовой, но не может реагировать на действия пользователя, вызывая гневные клики и отказы.С React мы можем использовать модуль
ReactDOMServer
на сервере Node, таком как Express, а затем вызвать методrenderToString
для отображения компонентов верхнего уровня в виде статической строки HTML.С Vue.js мы можем использовать vue-server-renderer для рендеринга экземпляра Vue в HTML с помощью
renderToString
. В Angular мы можем использовать@nguniversal
для превращения клиентских запросов в HTML-страницы, полностью отображаемые сервером. Кроме того, с помощью Next.js (React) или Nuxt.js (Vue) можно получить полностью серверную визуализацию.У подхода есть свои минусы. В результате мы получаем полную гибкость клиентских приложений, обеспечивая при этом более быстрый рендеринг на стороне сервера, но в итоге мы получаем более длительный разрыв между First Contentful Paint и Time To Interactive и увеличенную задержку первого ввода. Регидратация стоит очень дорого, и обычно одной этой стратегии недостаточно, поскольку она сильно задерживает время до взаимодействия.
- Потоковая передача на стороне сервера с прогрессивной гидратацией (SSR + CSR)
Чтобы свести к минимуму разрыв между Time To Interactive и First Contentful Paint, мы обрабатываем несколько запросов одновременно и отправляем контент частями по мере его создания. Таким образом, нам не нужно ждать полной строки HTML, прежде чем отправлять содержимое в браузер, и, следовательно, улучшить время до первого байта.В React вместо
renderToString()
мы можем использовать renderToNodeStream() для передачи ответа и отправки HTML по частям. В Vue мы можем использовать renderToStream(), который может передаваться по конвейеру и передаваться в потоковом режиме. С React Suspense мы также можем использовать асинхронный рендеринг для этой цели.На стороне клиента вместо загрузки всего приложения сразу мы загружаем компоненты постепенно . Разделы приложений сначала разбиваются на отдельные сценарии с разделением кода, а затем постепенно (в порядке наших приоритетов) гидратируются. Фактически, мы можем сначала гидратировать критически важные компоненты, а остальные можно гидратировать позже. Затем роль рендеринга на стороне клиента и на стороне сервера может быть определена по-разному для каждого компонента. Затем мы также можем отложить гидратацию некоторых компонентов до тех пор, пока они не появятся в поле зрения или потребуются для взаимодействия с пользователем, или пока браузер не будет бездействовать.
Для Vue Маркус Оберленер опубликовал руководство по сокращению времени до взаимодействия приложений SSR с помощью гидратации при взаимодействии с пользователем, а также vue-lazy-hydration, плагина ранней стадии, который включает гидратацию компонентов при видимости или конкретном взаимодействии с пользователем. Команда Angular работает над прогрессивным увлажнением с помощью Ivy Universal. Вы также можете реализовать частичную гидратацию с помощью Preact и Next.js.
- Трисоморфный рендеринг
Имея сервис-воркеров, мы можем использовать рендеринг потокового сервера для начальных/не-JS-навигаций, а затем заставлять сервис-воркер рендерить HTML для навигации после его установки. В этом случае сервисный работник выполняет предварительную визуализацию контента и включает навигацию в стиле SPA для визуализации новых представлений в том же сеансе. Хорошо работает, когда вы можете совместно использовать один и тот же код шаблонов и маршрутизации между сервером, клиентской страницей и работником службы.
- CSR с предварительным рендерингом
Предварительный рендеринг похож на рендеринг на стороне сервера, но вместо динамического рендеринга страниц на сервере мы визуализируем приложение в статический HTML во время сборки. В то время как статические страницы полностью интерактивны без большого количества клиентского JavaScript, предварительный рендеринг работает по-другому . По сути, он фиксирует начальное состояние клиентского приложения в виде статического HTML во время сборки, в то время как с предварительным рендерингом приложение должно быть загружено на клиенте, чтобы страницы были интерактивными.С помощью Next.js мы можем использовать статический экспорт HTML, предварительно отрендерив приложение в статический HTML. В Gatsby, генераторе статических сайтов с открытым исходным кодом, использующем React, во время сборки используется метод
renderToStaticMarkup
вместо методаrenderToString
, при этом основной фрагмент JS предварительно загружается, а будущие маршруты предварительно выбираются без атрибутов DOM, которые не нужны для простых статических страниц.Для Vue мы можем использовать Vuepress для достижения той же цели. Вы также можете использовать prerender-loader с Webpack. Navi также обеспечивает статический рендеринг.
В результате улучшается время до первого байта и первая отрисовка по содержанию, и мы уменьшаем разрыв между временем до интерактивности и первой отрисовкой по содержанию. Мы не можем использовать этот подход, если ожидается, что контент сильно изменится. Кроме того, все URL-адреса должны быть известны заранее, чтобы сгенерировать все страницы. Таким образом, некоторые компоненты могут быть отрисованы с использованием предварительной отрисовки, но если нам нужно что-то динамическое, мы должны полагаться на приложение для получения содержимого.
- Полный рендеринг на стороне клиента (CSR)
Вся логика, рендеринг и загрузка выполняются на клиенте. Результатом обычно является огромный разрыв между Time To Interactive и First Contentful Paint. В результате приложения часто чувствуют себя вялыми , поскольку все приложение должно быть загружено на клиенте, чтобы отобразить что-либо.Поскольку у JavaScript есть издержки производительности, поскольку объем JavaScript растет вместе с приложением, агрессивное разделение кода и отсрочка JavaScript будут абсолютно необходимы для сдерживания влияния JavaScript. В таких случаях рендеринг на стороне сервера обычно будет лучшим подходом, если не требуется много интерактивности. Если это не вариант, рассмотрите возможность использования модели оболочки приложения.
В общем, SSR быстрее, чем CSR. Тем не менее, это довольно частая реализация для многих приложений.
Итак, на стороне клиента или на стороне сервера? В целом рекомендуется ограничить использование полностью клиентских фреймворков страницами, которые в них абсолютно необходимы. Для продвинутых приложений также не рекомендуется полагаться только на рендеринг на стороне сервера. И рендеринг на сервере, и рендеринг на клиенте — это катастрофа, если они сделаны плохо.
Независимо от того, склоняетесь ли вы к CSR или SSR, убедитесь, что вы рендерите важные пиксели как можно скорее и минимизируете разрыв между этим рендерингом и временем до интерактивности. Подумайте о предварительном рендеринге, если ваши страницы не сильно меняются, и по возможности отложите загрузку фреймворков. Потоковая передача HTML фрагментами с рендерингом на стороне сервера и внедрение прогрессивной гидратации для рендеринга на стороне клиента — и гидратация при видимости, взаимодействии или во время простоя, чтобы получить лучшее из обоих миров.
- Полный рендеринг на стороне сервера (SSR)
- Сколько мы можем обслуживать статически?
Независимо от того, работаете ли вы над большим приложением или небольшим сайтом, стоит подумать о том, какой контент можно обслуживать статически из CDN (т. е. стека JAM), а не генерировать динамически «на лету». Даже если у вас есть тысячи продуктов и сотни фильтров с множеством вариантов персонализации, вы все равно можете статически обслуживать важные целевые страницы и отделять эти страницы от выбранной вами структуры.Существует множество генераторов статических сайтов, и страницы, которые они генерируют, зачастую очень быстрые. Чем больше контента мы сможем заранее создать вместо того, чтобы генерировать просмотры страниц на сервере или клиенте во время запроса, тем большей производительности мы добьемся.
В книге «Создание частично гидратированных статических веб-сайтов с прогрессивным улучшением» Маркус Оберленер показывает, как создавать веб-сайты с помощью генератора статических сайтов и SPA, добиваясь прогрессивного улучшения и минимального размера пакета JavaScript. Маркус использует Eleventy и Preact в качестве своих инструментов и показывает, как настроить инструменты, добавить частичную гидратацию, ленивую гидратацию, файл записи клиента, настроить Babel для Preact и связать Preact с Rollup — от начала до конца.
В наши дни, когда JAMStack используется на крупных сайтах, появился новый фактор производительности: время сборки . На самом деле, создание даже тысяч страниц при каждом новом развертывании может занять несколько минут, поэтому обещают увидеть инкрементные сборки в Gatsby, которые сократят время сборки в 60 раз благодаря интеграции с популярными решениями CMS, такими как WordPress, Contentful, Drupal, Netlify CMS. и другие.
Кроме того, Next.js анонсировал заблаговременную и инкрементную генерацию статических данных, что позволяет нам добавлять новые статические страницы во время выполнения и обновлять существующие страницы после того, как они уже созданы, путем повторного рендеринга их в фоновом режиме по мере поступления трафика. .
Нужен еще более легкий подход? В своем выступлении об Eleventy, Alpine и Tailwind: на пути к облегченному Jamstack Никола Гутей объясняет различия между CSR, SSR и всем, что между ними, и показывает, как использовать более легкий подход — вместе с репозиторием GitHub, который показывает этот подход. на практике.
- Рассмотрите возможность использования шаблона PRPL и архитектуры оболочки приложения.
Различные фреймворки по-разному влияют на производительность и требуют разных стратегий оптимизации, поэтому вы должны четко понимать все азы фреймворка, на который будете полагаться. При создании веб-приложения изучите шаблон PRPL и архитектуру оболочки приложения. Идея довольно проста: добавьте минимальный код, необходимый для интерактивности, чтобы начальный маршрут отображался быстро, затем используйте сервис-воркер для кэширования и предварительного кэширования ресурсов, а затем лениво загружайте нужные вам маршруты асинхронно.
- Вы оптимизировали производительность своих API?
API — это каналы связи, с помощью которых приложение может предоставлять данные внутренним и сторонним приложениям через конечные точки . При разработке и создании API нам нужен разумный протокол для обеспечения связи между сервером и сторонними запросами. Передача репрезентативного состояния ( REST ) — это хорошо зарекомендовавший себя логичный выбор: он определяет набор ограничений, которым следуют разработчики, чтобы сделать контент доступным производительным, надежным и масштабируемым образом. Веб-службы, соответствующие ограничениям REST, называются веб-службами RESTful .Как и в случае со старыми добрыми HTTP-запросами, когда данные извлекаются из API, любая задержка в ответе сервера будет распространяться на конечного пользователя, что приведет к задержке рендеринга . Когда ресурс хочет получить некоторые данные из API, ему нужно будет запросить данные из соответствующей конечной точки. Компоненту, отображающему данные из нескольких ресурсов, например статьи с комментариями и авторскими фотографиями в каждом комментарии, может потребоваться несколько обращений к серверу, чтобы получить все данные, прежде чем их можно будет отобразить. Кроме того, количество данных, возвращаемых через REST, часто превышает то, что необходимо для рендеринга этого компонента.
Если многим ресурсам требуются данные из API, API может стать узким местом в производительности. GraphQL предлагает эффективное решение этих проблем. По сути, GraphQL — это язык запросов для вашего API и среда выполнения на стороне сервера для выполнения запросов с использованием системы типов, которую вы определяете для своих данных. В отличие от REST, GraphQL может извлекать все данные в одном запросе , и ответ будет именно таким, какой требуется, без избыточной или недостаточной выборки данных, как это обычно происходит с REST.
Кроме того, поскольку GraphQL использует схему (метаданные, которые сообщают, как структурированы данные), он уже может организовывать данные в предпочтительную структуру, поэтому, например, с GraphQL мы могли бы удалить код JavaScript, используемый для управления состоянием, создавая более чистый код приложения, который быстрее работает на клиенте.
Если вы хотите начать работу с GraphQL или столкнулись с проблемами производительности, эти статьи могут оказаться весьма полезными:
- Учебник по GraphQL: зачем нам нужен новый вид API, Эрик Баер,
- Учебник по GraphQL: эволюция дизайна API, Эрик Баер,
- Разработка сервера GraphQL для оптимальной производительности Леонардо Лосовица,
- Производительность GraphQL объяснил Войцех Троцкий.
- Будете ли вы использовать AMP или Instant Articles?
В зависимости от приоритетов и стратегии вашей организации вы можете рассмотреть возможность использования Google AMP, Instant Articles от Facebook или Apple News от Apple. Вы можете добиться хорошей производительности и без них, но AMP обеспечивает надежную основу производительности с бесплатной сетью доставки контента (CDN), а Instant Articles повысит вашу видимость и производительность на Facebook.Казалось бы очевидным преимуществом этих технологий для пользователей является гарантированная производительность , поэтому иногда они могут даже предпочесть AMP-/Apple News/Instant Pages-ссылки «обычным» и потенциально раздутым страницам. Для веб-сайтов с большим количеством контента, которые имеют дело с большим количеством стороннего контента, эти параметры потенциально могут значительно ускорить время рендеринга.
Если только они этого не сделают. По словам Тима Кадлека, например, «документы AMP, как правило, быстрее, чем их аналоги, но это не обязательно означает, что страница является производительной. AMP — это не то, что имеет самое большое значение с точки зрения производительности».
Выгода для владельца веб-сайта очевидна: возможность обнаружения этих форматов на соответствующих платформах и повышенная видимость в поисковых системах.
Ну, по крайней мере, так было раньше. Поскольку AMP больше не является обязательным требованием для Top Stories , издатели могут вместо этого перейти от AMP к традиционному стеку ( спасибо, Барри! ).
Тем не менее, вы также можете создавать прогрессивные веб-AMP, повторно используя AMP в качестве источника данных для вашего PWA. Недостатки? Очевидно, что присутствие в огороженном саду дает разработчикам возможность создавать и поддерживать отдельную версию своего контента, а в случае Instant Articles и Apple News без фактических URL-адресов (спасибо, Эдди, Джереми!) .
- Выбирайте CDN с умом.
Как упоминалось выше, в зависимости от того, сколько у вас динамических данных, вы можете «аутсорсить» некоторую часть контента генератору статических сайтов, отправляя его в CDN и обслуживая оттуда статическую версию, тем самым избегая запросов к сервер. Фактически, некоторые из этих генераторов на самом деле являются компиляторами веб-сайтов с множеством автоматических оптимизаций, предоставляемых из коробки. По мере того как компиляторы со временем добавляют оптимизацию, скомпилированный вывод со временем становится меньше и быстрее.Обратите внимание, что CDN также могут обслуживать (и разгружать) динамический контент. Таким образом, ограничивать CDN статическими активами не обязательно. Дважды проверьте, выполняет ли ваш CDN сжатие и преобразование (например, оптимизацию изображений и изменение размера на периферии), обеспечивают ли они поддержку рабочих серверов, A/B-тестирование, а также периферийные включения, которые объединяют статические и динамические части страниц. на границе CDN (т. е. ближайший к пользователю сервер) и другие задачи. Также проверьте, поддерживает ли ваш CDN HTTP через QUIC (HTTP/3).
Кэти Хемпениус написала фантастическое руководство по CDN, в котором рассказывается о том, как выбрать хорошую CDN , как ее настроить, а также обо всех мелочах, которые следует учитывать при ее оценке. Как правило, рекомендуется максимально агрессивно кэшировать содержимое и включать функции повышения производительности CDN, такие как Brotli, TLS 1.3, HTTP/2 и HTTP/3.
Примечание . Согласно исследованиям Патрика Минана и Энди Дэвиса, приоритизация HTTP/2 фактически нарушена во многих CDN, поэтому будьте осторожны при выборе CDN. У Патрика есть более подробная информация в его докладе о приоритизации HTTP/2 ( спасибо, Барри! ).
При выборе CDN вы можете использовать эти сравнительные сайты с подробным обзором их функций:
- Сравнение CDN, матрица сравнения CDN для Cloudfront, Aazure, KeyCDN, Fastly, Verizon, Stackpach, Akamai и многих других.
- CDN Perf измеряет скорость запросов для CDN, собирая и анализируя 300 миллионов тестов каждый день, причем все результаты основаны на данных RUM от пользователей со всего мира. Также проверьте сравнение производительности DNS и сравнение производительности облака.
- CDN Planet Guides предоставляет обзор CDN по конкретным темам, таким как Serve Stale, Purge, Origin Shield, Prefetch и Compression.
- Веб-альманах: принятие и использование CDN предоставляет информацию о ведущих поставщиках CDN, их управлении RTT и TLS, времени согласования TLS, внедрении HTTP/2 и многом другом. (К сожалению, данные только за 2019 год).
Оптимизация активов
- Используйте Brotli для сжатия простого текста.
В 2015 году Google представила Brotli, новый формат данных без потерь с открытым исходным кодом, который теперь поддерживается во всех современных браузерах. Библиотека Brotli с открытым исходным кодом, которая реализует кодировщик и декодер для Brotli, имеет 11 предопределенных уровней качества для кодировщика, при этом более высокий уровень качества требует больше ресурсов ЦП в обмен на лучшую степень сжатия. Более медленное сжатие в конечном итоге приведет к более высокой скорости сжатия, но тем не менее Brotli быстро распаковывает. Однако стоит отметить, что Brotli с уровнем сжатия 4 меньше и сжимает быстрее, чем Gzip.На практике Brotli оказывается намного эффективнее, чем Gzip. Мнения и опыт различаются, но если ваш сайт уже оптимизирован с помощью Gzip, вы можете ожидать, по крайней мере, однозначных улучшений и, в лучшем случае, двузначных улучшений в уменьшении размера и времени FCP. Вы также можете оценить экономию сжатия Brotli для вашего сайта.
Браузеры будут принимать Brotli, только если пользователь посещает веб-сайт через HTTPS. Brotli широко поддерживается, и многие CDN поддерживают его (Akamai, Netlify Edge, AWS, KeyCDN, Fastly (в настоящее время только как сквозной), Cloudflare, CDN77), и вы можете включить Brotli даже на CDN, которые еще не поддерживают его. (с обслуживающим персоналом).
Загвоздка в том, что, поскольку сжатие всех ресурсов с помощью Brotli при высоком уровне сжатия обходится дорого, многие хостинг-провайдеры не могут использовать его в полном объеме только из-за огромных накладных расходов, которые он создает. На самом деле, на самом высоком уровне сжатия Brotli работает настолько медленно, что любое потенциальное увеличение размера файла может быть сведено на нет из-за времени, которое требуется серверу, чтобы начать отправку ответа, поскольку он ожидает динамического сжатия ресурса. (Но если у вас есть время во время сборки со статическим сжатием, конечно, предпочтительны более высокие настройки сжатия.)
Хотя это может измениться. Формат файла Brotli включает встроенный статический словарь и, помимо того, что он содержит различные строки на нескольких языках, также поддерживает возможность применения нескольких преобразований к этим словам, что повышает его универсальность. В своем исследовании Феликс Ханау обнаружил способ улучшить сжатие на уровнях с 5 по 9, используя «более специализированное подмножество словаря, чем по умолчанию» и полагаясь на заголовок
Content-Type
, чтобы указать компрессору, следует ли ему использовать словарь для HTML, JavaScript или CSS. Результатом было «незначительное влияние на производительность (на 1-3% больше ЦП по сравнению с 12% в обычном режиме) при сжатии веб-контента на высоких уровнях сжатия с использованием подхода с ограниченным использованием словаря».Кроме того, благодаря исследованиям Елены Кириленко мы можем добиться быстрой и эффективной повторной компрессии Brotli , используя предыдущие артефакты сжатия. По словам Елены, «когда у нас есть ресурс, сжатый с помощью Brotli, и мы пытаемся сжимать динамический контент «на лету», когда контент напоминает контент, доступный нам заранее, мы можем добиться значительного улучшения времени сжатия. "
Как часто это бывает? Например, с доставкой подмножеств пакетов JavaScript (например, когда части кода уже кэшированы на клиенте или с динамическим пакетом, обслуживающим WebBundles). Или с динамическим HTML, основанным на заранее известных шаблонах, или с динамическим подмножеством шрифтов WOFF2 . По словам Елены, мы можем получить улучшение сжатия на 5,3% и улучшение скорости сжатия на 39% при удалении 10% контента, а также повышение скорости сжатия на 3,2% и ускорение сжатия на 26% при удалении 50% контента.
Сжатие Brotli становится лучше, поэтому, если вы можете обойти затраты на динамическое сжатие статических ресурсов, это определенно стоит затраченных усилий. Само собой разумеется, что Brotli можно использовать для любой полезной нагрузки открытого текста — HTML, CSS, SVG, JavaScript, JSON и так далее.
Примечание . По состоянию на начало 2021 года примерно 60 % HTTP-ответов доставляются без текстового сжатия, 30,82 % сжимаются с помощью Gzip и 9,1 % со сжатием с помощью Brotli (как на мобильных устройствах, так и на настольных компьютерах). Например, 23,4% страниц Angular не сжаты (через gzip или Brotli). Тем не менее, часто включение сжатия является одним из самых простых способов повысить производительность простым щелчком переключателя.
Стратегия? Предварительно сжимайте статические ресурсы с помощью Brotli+Gzip на самом высоком уровне и сжимайте (динамический) HTML на лету с помощью Brotli на уровне 4–6. Убедитесь, что сервер правильно обрабатывает согласование содержимого для Brotli или Gzip.
- Используем ли мы адаптивную загрузку мультимедиа и клиентские подсказки?
Это пришло из страны старых новостей, но это всегда хорошее напоминание об использовании адаптивных изображений сsrcset
,sizes
и элементом<picture>
. Специально для сайтов с большим количеством носителей мы можем сделать еще один шаг вперед с адаптивной загрузкой мультимедиа (в этом примере React + Next.js), предоставляя легкий опыт для медленных сетей и устройств с малым объемом памяти и полный опыт для быстрой сети и высокой производительности. -устройства памяти. В контексте React мы можем добиться этого с помощью клиентских подсказок на сервере и реактивных адаптивных хуков на клиенте.Будущее адаптивных изображений может резко измениться с более широким внедрением клиентских подсказок. Подсказки клиента — это поля заголовка HTTP-запроса, например,
DPR
,Viewport-Width
,Width
,Save-Data
,Accept
(для указания предпочтений формата изображения) и другие. Они должны информировать сервер об особенностях браузера пользователя, экрана, подключения и т. д.В результате сервер может решить, как заполнить макет изображениями подходящего размера , и обслуживать только эти изображения в нужных форматах. С помощью клиентских подсказок мы перемещаем выбор ресурсов из HTML-разметки в процесс согласования запроса и ответа между клиентом и сервером.
Как заметил Илья Григорик, клиентские подсказки дополняют картину — они не являются альтернативой адаптивным изображениям. «Элемент
<picture>
обеспечивает необходимое управление художественным оформлением в HTML-разметке. Подсказки клиента предоставляют аннотации к полученным запросам изображений, что позволяет автоматизировать выбор ресурсов. Service Worker предоставляет полные возможности управления запросами и ответами на клиенте».Сервисный работник может, например, добавить новые значения заголовков подсказок клиента к запросу, переписать URL-адрес и направить запрос изображения в CDN, адаптировать ответ на основе подключения и пользовательских предпочтений и т. д. Это верно не только для ресурсов изображений, но почти для всех других запросов.
Для клиентов, поддерживающих клиентские подсказки, можно было измерить 42% экономии байтов на изображениях и на 1 МБ+ меньше байтов для 70-го+ процентиля. На Smashing Magazine мы также смогли измерить улучшение на 19-32%. Клиентские подсказки поддерживаются в браузерах на основе Chromium, но в Firefox они все еще находятся на рассмотрении.
Однако если вы укажете как обычную разметку адаптивных изображений, так и
<meta>
для клиентских подсказок, поддерживающий браузер оценит разметку адаптивных изображений и запросит соответствующий источник изображения, используя HTTP-заголовки клиентских подсказок. - Используем ли мы адаптивные изображения для фоновых изображений?
Мы обязательно должны! С помощьюimage-set
, который теперь поддерживается в Safari 14 и в большинстве современных браузеров, кроме Firefox, мы также можем отображать адаптивные фоновые изображения:background-image: url("fallback.jpg"); background-image: image-set( "photo-small.jpg" 1x, "photo-large.jpg" 2x, "photo-print.jpg" 600dpi);
По сути, мы можем условно обслуживать фоновые изображения с низким разрешением с дескриптором
1x
, изображения с более высоким разрешением с дескриптором2x
и даже изображение качества печати с дескриптором600dpi
. Однако будьте осторожны: браузеры не предоставляют никакой специальной информации о фоновых изображениях вспомогательным технологиям, поэтому в идеале эти фотографии будут просто украшением. - Используем ли мы WebP?
Сжатие изображений часто считается быстрой победой, но на практике оно все еще используется недостаточно. Конечно, изображения не блокируют рендеринг, но они сильно влияют на плохие оценки LCP, и очень часто они слишком тяжелые и слишком большие для устройства, на котором они используются.Так что, по крайней мере, мы могли бы изучить использование формата WebP для наших изображений. Фактически, сага WebP близится к концу в прошлом году, когда Apple добавила поддержку WebP в Safari 14. Итак, после многих лет дискуссий и дебатов, на сегодняшний день WebP поддерживается во всех современных браузерах. Таким образом, мы можем обслуживать изображения WebP с элементом
<picture>
и запасным вариантом JPEG, если это необходимо (см. фрагмент кода Андреаса Бовенса) или с помощью согласования содержимого (используя заголовкиAccept
).Однако WebP не лишен недостатков . Несмотря на то, что размеры файла изображения WebP по сравнению с эквивалентными Guetzli и Zopfli, этот формат не поддерживает прогрессивный рендеринг, такой как JPEG, поэтому пользователи могут быстрее увидеть готовое изображение со старым добрым JPEG, хотя изображения WebP могут становиться быстрее через сеть. С JPEG мы можем обслуживать «достойный» пользовательский интерфейс с половиной или даже четвертью данных и загружать остальные позже, вместо того, чтобы иметь полупустое изображение, как в случае WebP.
Ваше решение будет зависеть от того, что вам нужно: с WebP вы уменьшите полезную нагрузку, а с JPEG вы улучшите воспринимаемую производительность. Вы можете узнать больше о WebP в выступлении Паскаля Массимино из Google.
Для преобразования в WebP вы можете использовать WebP Converter, cwebp или libwebp. У Айра Адеринокуна также есть очень подробное руководство по преобразованию изображений в WebP, как и у Джоша Комо в его статье о работе с современными форматами изображений.
Sketch изначально поддерживает WebP, а изображения WebP можно экспортировать из Photoshop с помощью подключаемого модуля WebP для Photoshop. Но возможны и другие варианты.
Если вы используете WordPress или Joomla, существуют расширения, которые помогут вам легко реализовать поддержку WebP, такие как Optimus и Cache Enabler для WordPress и собственное поддерживаемое расширение Joomla (через Коди Арсено). Вы также можете абстрагироваться от элемента
<picture>
с помощью React, стилизованных компонентов или gatsby-image.Ах — бессовестная вилка! — Джереми Вагнер даже опубликовал потрясающую книгу о WebP, с которой вы, возможно, захотите ознакомиться, если вас интересует все, что связано с WebP.
- Используем ли мы AVIF?
Возможно, вы уже слышали важные новости: AVIF приземлился. Это новый формат изображения, полученный из ключевых кадров видео AV1. Это открытый, бесплатный формат, который поддерживает сжатие с потерями и без потерь, анимацию, альфа-канал с потерями и может обрабатывать четкие линии и сплошные цвета (что было проблемой с JPEG), обеспечивая при этом лучшие результаты в обоих случаях.На самом деле, по сравнению с WebP и JPEG, AVIF работает значительно лучше , обеспечивая экономию среднего размера файла до 50% при том же DSSIM ((не)подобие между двумя или более изображениями с использованием алгоритма, близкого к человеческому зрению). На самом деле, в своем подробном посте об оптимизации загрузки изображений Мальте Убл отмечает, что AVIF «очень последовательно превосходит JPEG в очень значительном смысле. потери из-за отсутствия поддержки прогрессивной загрузки».
Как ни странно, AVIF может работать даже лучше, чем большие SVG, хотя, конечно, его не следует рассматривать как замену SVG. Это также один из первых форматов изображений, поддерживающих поддержку цвета HDR; предлагая более высокую яркость, глубину цвета и цветовую гамму. Единственным недостатком является то, что в настоящее время AVIF не поддерживает прогрессивное декодирование изображений (пока?) и, как и Brotli, кодирование с высокой степенью сжатия в настоящее время довольно медленное, хотя декодирование быстрое.
В настоящее время AVIF поддерживается в Chrome, Firefox и Opera, и ожидается, что поддержка в Safari появится в ближайшее время (поскольку Apple является членом группы, создавшей AV1).
Каков наилучший способ подачи изображений в наши дни ? Для иллюстраций и векторных изображений (сжатый) SVG, несомненно, лучший выбор. Для фотографий мы используем методы согласования контента с элементом
picture
. Если AVIF поддерживается, мы отправляем изображение AVIF; если это не так, мы сначала возвращаемся к WebP, а если WebP также не поддерживается, мы переключаемся на JPEG или PNG в качестве резерва (при необходимости применяя условия@media
):<picture> <source type="image/avif"> <source type="image/webp"> <img src="image.jpg" alt="Photo" width="450" height="350"> </picture>
Честно говоря, более вероятно, что мы будем использовать некоторые условия в элементе
picture
:<picture> <source type="image/avif" /> <source type="image/webp" /> <source type="image/jpeg" /> <img src="fallback-image.jpg" alt="Photo" width="450" height="350"> </picture>
<picture> <source type="image/avif" /> <source type="image/webp" /> <source type="image/jpeg" /> <img src="fallback-image.jpg" alt="Photo" width="450" height="350"> </picture>
Вы можете пойти еще дальше, заменив анимированные изображения статическими изображениями для клиентов, которые соглашаются на меньшее движение с помощью
prefers-reduced-motion
:<picture> <source media="(prefers-reduced-motion: reduce)" type="image/avif"></source> <source media="(prefers-reduced-motion: reduce)" type="image/jpeg"></source> <source type="image/avif"></source> <img src="motion.jpg" alt="Animated AVIF"> </picture>
<picture> <source media="(prefers-reduced-motion: reduce)" type="image/avif"></source> <source media="(prefers-reduced-motion: reduce)" type="image/jpeg"></source> <source type="image/avif"></source> <img src="motion.jpg" alt="Animated AVIF"> </picture>
За пару месяцев AVIF набрал обороты:
- Мы можем протестировать резервные варианты WebP/AVIF на панели Rendering в DevTools.
- Мы можем использовать Squoosh, AVIF.io и libavif для кодирования, декодирования, сжатия и преобразования файлов AVIF.
- Мы можем использовать компонент AVIF Preact Джейка Арчибальда, который декодирует AVIF-файл в воркере и отображает результат на холсте,
- Чтобы предоставить AVIF только поддерживающим браузерам, мы можем использовать плагин PostCSS вместе со скриптом 315B для использования AVIF в ваших объявлениях CSS.
- Мы можем постепенно предоставлять новые форматы изображений с помощью CSS и Cloudlare Workers, чтобы динамически изменять возвращаемый HTML-документ, выводя информацию из заголовка
accept
, а затем добавляяwebp/avif
и т. д. по мере необходимости. - AVIF уже доступен в Cloudinary (с ограничениями на использование), Cloudflare поддерживает AVIF при изменении размера изображения, и вы можете включить AVIF с пользовательскими заголовками AVIF в Netlify.
- Когда дело доходит до анимации, AVIF работает так же, как
<img src=mp4>
в Safari, превосходя GIF и WebP в целом, но MP4 по-прежнему работает лучше. - В общем, для анимации AVC1 (h264) > HVC1 > WebP > AVIF > GIF, при условии, что браузеры на основе Chromium когда-либо будут поддерживать
<img src=mp4>
. - Вы можете найти более подробную информацию об AVIF в AVIF for Next Generation Image Coding в докладе Адитьи Мавланкар из Netflix и в докладе Корнела Лесински из Cloudflare о формате изображения.
- Отличный справочник по всему AVIF: подробный пост Джейка Арчибальда на AVIF приземлился.
Так есть ли будущее в AVIF ? Джон Снейерс не согласен: AVIF работает на 60% хуже, чем JPEG XL, еще один бесплатный и открытый формат, разработанный Google и Cloudinary. На самом деле, JPEG XL, кажется, работает намного лучше по всем направлениям. Однако JPEG XL все еще находится на завершающей стадии стандартизации и еще не работает ни в одном браузере. (Не путать с JPEG-XR от Microsoft, исходящим из старого доброго Internet Explorer 9 раз).
- Правильно ли оптимизированы JPEG/PNG/SVG?
Когда вы работаете над целевой страницей, на которой очень важно, чтобы главное изображение загружалось молниеносно быстро, убедитесь, что файлы JPEG являются прогрессивными и сжаты с помощью mozJPEG (который сокращает время начального рендеринга за счет управления уровнями сканирования) или Guetzli, Google с открытым исходным кодом. кодировщик, ориентированный на производительность восприятия и использующий знания Zopfli и WebP. Единственный недостаток: медленное время обработки (минута процессора на мегапиксель).Для PNG мы можем использовать Pingo, а для SVG мы можем использовать SVGO или SVGOMG. И если вам нужно быстро просмотреть и скопировать или загрузить все ресурсы SVG с веб-сайта, svg-grabber может сделать это за вас.
Об этом говорится в каждой статье по оптимизации изображений, но всегда стоит упомянуть о чистоте и аккуратности векторных ресурсов. Обязательно очистите неиспользуемые активы, удалите ненужные метаданные и уменьшите количество точек пути в иллюстрации (и, следовательно, в коде SVG). ( Спасибо, Джереми! )
Однако есть и полезные онлайн-инструменты:
- Используйте Squoosh для сжатия, изменения размера и управления изображениями с оптимальным уровнем сжатия (с потерями или без потерь),
- Используйте Guetzli.it для сжатия и оптимизации изображений JPEG с помощью Guetzli, который хорошо работает с изображениями с четкими краями и сплошными цветами (но может быть немного медленнее)).
- Используйте Генератор контрольных точек адаптивного изображения или такой сервис, как Cloudinary или Imgix, для автоматизации оптимизации изображения. Кроме того, во многих случаях использование
srcset
иsizes
дает значительные преимущества. - Чтобы проверить эффективность вашей адаптивной разметки, вы можете использовать images-heap, инструмент командной строки, который измеряет эффективность в зависимости от размера окна просмотра и соотношения пикселей устройства.
- Вы можете добавить автоматическое сжатие изображений в свои рабочие процессы GitHub, чтобы ни одно изображение не попадало в рабочую среду без сжатия. Экшен использует mozjpeg и libvips, которые работают с PNG и JPG.
- Чтобы оптимизировать внутреннюю память, вы можете использовать новый формат Dropbox Lepton для сжатия файлов JPEG без потерь в среднем на 22%.
- Используйте BlurHash, если вы хотите показать замещающее изображение заранее. BlurHash берет изображение и дает вам короткую строку (всего 20-30 символов!), которая представляет собой заполнитель для этого изображения. Строка достаточно короткая, чтобы ее можно было легко добавить как поле в объект JSON.
Иногда оптимизация изображений сама по себе не помогает. Чтобы сократить время, необходимое для запуска рендеринга важного изображения, отложите загрузку менее важных изображений и отложите загрузку любых скриптов после того, как критические изображения уже отрендерены. Наиболее надежным способом является гибридная отложенная загрузка, когда мы используем нативную отложенную загрузку и отложенную загрузку, библиотеку, которая обнаруживает любые изменения видимости, вызванные взаимодействием с пользователем (с помощью IntersectionObserver, который мы рассмотрим позже). Кроме того:
- Рассмотрите возможность предварительной загрузки важных изображений, чтобы браузер не обнаружил их слишком поздно. Для фоновых изображений, если вы хотите быть еще более агрессивным, вы можете добавить изображение как обычное изображение с помощью
<img src>
, а затем скрыть его с экрана. - Рассмотрите возможность замены изображений с помощью атрибута Sizes, указав различные размеры отображения изображения в зависимости от медиа-запросов, например, чтобы управлять
sizes
для замены источников в компоненте лупы. - Проверьте несоответствия загрузки изображений, чтобы предотвратить неожиданную загрузку изображений переднего плана и фона. Следите за изображениями, которые загружаются по умолчанию, но могут никогда не отображаться — например, в каруселях, аккордеонах и галереях изображений.
- Всегда устанавливайте
width
иheight
изображений. Обратите внимание на свойствоaspect-ratio
в CSS и атрибутintrinsicsize
размера, который позволит нам устанавливать пропорции и размеры для изображений, чтобы браузер мог заранее зарезервировать заранее определенный слот макета, чтобы избежать скачков макета во время загрузки страницы.
Если вы чувствуете себя предприимчивым, вы можете обрезать и переупорядочивать потоки HTTP/2, используя Edge Workers, в основном фильтр в реальном времени, живущий в CDN, для более быстрой отправки изображений по сети. Пограничные рабочие используют потоки JavaScript, которые используют фрагменты, которыми вы можете управлять (по сути, это JavaScript, работающий на краю CDN, который может изменять потоковые ответы), поэтому вы можете контролировать доставку изображений.
С сервис-воркером уже слишком поздно, так как вы не можете контролировать то, что передается по сети, но он работает с пограничными работниками. Таким образом, вы можете использовать их поверх статических файлов JPEG, постепенно сохраняемых для конкретной целевой страницы.
Не достаточно хорош? Что ж, вы также можете улучшить воспринимаемую производительность для изображений с помощью метода множественных фоновых изображений. Имейте в виду, что игра с контрастом и размытие ненужных деталей (или удаление цветов) также могут уменьшить размер файла. Ах, вам нужно увеличить маленькое фото без потери качества? Рассмотрите возможность использования Letsenhance.io.
Эти оптимизации пока охватывают только основы. Эдди Османи опубликовала очень подробное руководство по Essential Image Optimization, в котором подробно рассказывается о сжатии изображений и управлении цветом. Например, вы можете размыть ненужные части изображения (применив к ним фильтр размытия по Гауссу), чтобы уменьшить размер файла, и в конечном итоге вы можете даже начать удалять цвета или превратить изображение в черно-белое, чтобы еще больше уменьшить размер. . Для фоновых изображений экспорт фотографий из Photoshop с качеством от 0 до 10% также может быть абсолютно приемлемым.
В Smashing Magazine мы используем постфикс
-opt
для имен изображений — например,brotli-compression-opt.png
; всякий раз, когда изображение содержит этот постфикс, все в команде знают, что изображение уже оптимизировано.Ах, и не используйте JPEG-XR в Интернете — «обработка декодирования JPEG-XR на стороне программного обеспечения на ЦП сводит на нет и даже перевешивает потенциально положительное влияние экономии размера байта, особенно в контексте SPA» (не чтобы перепутать с Cloudinary / Google JPEG XL).
- Правильно ли оптимизированы видео?
До сих пор мы рассматривали изображения, но избегали разговоров о старых добрых GIF-файлах. Несмотря на нашу любовь к GIF, пришло время отказаться от них навсегда (по крайней мере, в наших веб-сайтах и приложениях). Вместо того, чтобы загружать тяжелые анимированные GIF-файлы, которые влияют как на производительность рендеринга, так и на пропускную способность, рекомендуется переключиться либо на анимированный WebP (где GIF является запасным вариантом), либо полностью заменить их зацикленными видео HTML5.В отличие от изображений, браузеры не загружают предварительно содержимое
<video>
, но видео HTML5, как правило, намного легче и меньше, чем GIF. Не вариант? Ну, по крайней мере, мы можем добавить сжатие с потерями к GIF с помощью Lossy GIF, gifsicle или giflossy.Тесты, проведенные Колином Бенделлом, показывают, что встроенные видео в тегах
img
в Safari Technology Preview отображаются по крайней мере в 20 раз быстрее и декодируются в 7 раз быстрее, чем эквивалент GIF, в дополнение к тому, что они имеют меньший размер файла. Однако он не поддерживается в других браузерах.В стране хороших новостей форматы видео стремительно развиваются на протяжении многих лет. Долгое время мы надеялись, что WebM станет форматом, который будет управлять ими всеми, а WebP (который, по сути, представляет собой одно неподвижное изображение внутри видеоконтейнера WebM) станет заменой устаревшим форматам изображений. Действительно, Safari теперь поддерживает WebP, но, несмотря на то, что WebP и WebM получили поддержку в наши дни, прорыва на самом деле не произошло.
Тем не менее, мы могли бы использовать WebM для большинства современных браузеров:
<!-- By Houssein Djirdeh. https://web.dev/replace-gifs-with-videos/ --> <!-- A common scenartio: MP4 with a WEBM fallback. --> <video autoplay loop muted playsinline> <source src="my-animation.webm" type="video/webm"> <source src="my-animation.mp4" type="video/mp4"> </video>
Но, возможно, мы могли бы вернуться к нему вообще. В 2018 году Альянс открытых медиа выпустил новый перспективный формат видео под названием AV1 . AV1 имеет сжатие, аналогичное кодеку H.265 (эволюция H.264), но в отличие от последнего, AV1 является бесплатным. Стоимость лицензии H.265 подтолкнула поставщиков браузеров к использованию вместо этого сравнительно производительного AV1: AV1 (точно так же, как H.265) сжимает в два раза лучше, чем WebM .
На самом деле Apple в настоящее время использует формат HEIF и HEVC (H.265), и все фото и видео на последней версии iOS сохраняются в этих форматах, а не в JPEG. В то время как HEIF и HEVC (H.265) не доступны должным образом в Интернете (пока?), AV1 — и получает поддержку браузеров. Поэтому добавление источника
AV1
в ваш<video>
разумно, так как все поставщики браузеров, похоже, согласны с этим.На данный момент наиболее широко используемой и поддерживаемой кодировкой является H.264, обслуживаемая файлами MP4, поэтому перед подачей файла убедитесь, что ваши MP4-файлы обработаны многопроходным кодированием, размыты эффектом frei0r iirblur (если применимо) и Метаданные атома moov перемещаются в заголовок файла, в то время как ваш сервер принимает обслуживание байтов. Борис Шапира дает точные инструкции для FFmpeg по максимальной оптимизации видео. Конечно, предоставление формата WebM в качестве альтернативы тоже помогло бы.
Нужно ускорить рендеринг видео, но видеофайлы все еще слишком велики ? Например, когда у вас есть большое фоновое видео на целевой странице? Обычный метод заключается в том, чтобы сначала показать самый первый кадр в виде неподвижного изображения или отобразить сильно оптимизированный короткий зацикленный сегмент, который можно интерпретировать как часть видео, а затем, когда видео будет достаточно буферизовано, начать воспроизведение. собственно видео. Дуг Силларс написал подробное руководство по производительности фонового видео, которое может быть полезно в этом случае. ( Спасибо, Гай Поджарный! ).
Для приведенного выше сценария вы можете предоставить адаптивные изображения постеров . По умолчанию элементы
video
позволяют использовать только одно изображение в качестве постера, что не всегда оптимально. Мы можем использовать Responsive Video Poster, библиотеку JavaScript, которая позволяет использовать разные изображения постеров для разных экранов, а также добавлять переходное наложение и полный контроль над стилем заполнителей видео.Исследование показывает, что качество видеопотока влияет на поведение зрителей. На самом деле зрители начинают отказываться от видео, если задержка запуска превышает примерно 2 секунды. После этого увеличение задержки на 1 секунду приводит к увеличению процента отказов примерно на 5,8%. Поэтому неудивительно, что среднее время начала видео составляет 12,8 с, при этом 40% видео имеют по крайней мере 1 остановку, а 20% - по крайней мере 2 секунды воспроизведения видео. На самом деле, зависания видео неизбежны в 3G, поскольку видео воспроизводится быстрее, чем сеть может предоставить контент.
Итак, каково решение? Обычно устройства с небольшим экраном не могут обрабатывать 720p и 1080p, которые мы обслуживаем на рабочем столе. По словам Дуга Силларса, мы можем либо создавать уменьшенные версии наших видео, либо использовать Javascript для определения источника для небольших экранов, чтобы обеспечить быстрое и плавное воспроизведение на этих устройствах. В качестве альтернативы мы можем использовать потоковое видео. Видеопотоки HLS будут доставлять на устройство видео соответствующего размера, что избавляет от необходимости создавать разные видео для разных экранов. Он также согласует скорость сети и адаптирует битрейт видео к скорости используемой вами сети.
Чтобы избежать потери полосы пропускания, мы могли добавить источник видео только для устройств, которые действительно могут хорошо воспроизводить видео. В качестве альтернативы мы можем вообще удалить
autoplay
из тегаvideo
и использовать JavaScript для вставкиautoplay
для больших экранов. Кроме того, нам нужно добавитьpreload="none"
кvideo
, чтобы указать браузеру не загружать какие -либо видеофайлы, пока он действительно не понадобится:<!-- Based on Doug Sillars's post. https://dougsillars.com/2020/01/06/hiding-videos-on-the-mbile-web/ --> <video preload="none" playsinline muted loop width="1920" height="1080" poster="poster.jpg"> <source src="video.webm" type="video/webm"> <source src="video.mp4" type="video/mp4"> </video>
Затем мы можем настроить таргетинг на браузеры, которые действительно поддерживают AV1:
<!-- Based on Doug Sillars's post. https://dougsillars.com/2020/01/06/hiding-videos-on-the-mbile-web/ --> <video preload="none" playsinline muted loop width="1920" height="1080" poster="poster.jpg"> <source src="video.av1.mp4" type="video/mp4; codecs=av01.0.05M.08"> <source src="video.hevc.mp4" type="video/mp4; codecs=hevc"> <source src="video.webm" type="video/webm"> <source src="video.mp4" type="video/mp4"> </video>
Затем мы могли бы повторно добавить
autoplay
выше определенного порога (например, 1000 пикселей):/* By Doug Sillars. https://dougsillars.com/2020/01/06/hiding-videos-on-the-mbile-web/ */ <script> window.onload = addAutoplay(); var videoLocation = document.getElementById("hero-video"); function addAutoplay() { if(window.innerWidth > 1000){ videoLocation.setAttribute("autoplay",""); }; } </script>
Производительность воспроизведения видео — это отдельная история, и если вы хотите погрузиться в нее подробнее, взгляните на другую серию статей Дуга Силларса «Текущее состояние видео и лучшие практики доставки видео», в которой подробно описаны показатели доставки видео. , предварительная загрузка видео, сжатие и потоковая передача. Наконец, вы можете проверить, насколько медленным или быстрым будет ваше потоковое видео с помощью Stream or Not.
- Оптимизирована ли доставка веб-шрифтов?
Первый вопрос, который стоит задать, заключается в том, можем ли мы вообще обойтись без использования системных шрифтов пользовательского интерфейса — нам просто нужно дважды проверить, правильно ли они отображаются на разных платформах. Если это не так, высока вероятность того, что веб-шрифты, которые мы обслуживаем, содержат глифы и дополнительные функции и веса, которые не используются. Мы можем попросить нашу компанию создать подмножество веб-шрифтов или, если мы используем шрифты с открытым исходным кодом, подмножить их самостоятельно с помощью Glyphhanger или Fontsquirrel. Мы даже можем автоматизировать весь наш рабочий процесс с помощью подшрифта Питера Мюллера, инструмента командной строки, который статически анализирует вашу страницу, чтобы создать наиболее оптимальные наборы веб-шрифтов, а затем внедрить их на наши страницы.Поддержка WOFF2 великолепна, и мы можем использовать WOFF в качестве запасного варианта для браузеров, которые его не поддерживают — или, возможно, устаревшие браузеры могут обслуживаться системными шрифтами. Существует много-много вариантов загрузки веб-шрифтов, и мы можем выбрать одну из стратегий из «Всеобъемлющего руководства по стратегиям загрузки шрифтов» Зака Лезермана (фрагменты кода также доступны в виде рецептов загрузки веб-шрифтов).
Вероятно, лучшими вариантами для рассмотрения сегодня являются критический FOFT с
preload
загрузкой и метод «Компромисс». Оба они используют двухэтапный рендеринг для поэтапной доставки веб-шрифтов — сначала небольшой надмножество, необходимое для быстрого и точного рендеринга страницы с помощью веб-шрифта, а затем асинхронная загрузка остальной части семейства. Разница в том, что метод «Компромисс» загружает полифилл асинхронно, только если события загрузки шрифта не поддерживаются, поэтому вам не нужно загружать полифилл по умолчанию. Нужна быстрая победа? У Zach Leatherman есть краткое 23-минутное руководство и тематическое исследование, чтобы привести шрифты в порядок.В общем, может быть хорошей идеей использовать подсказку ресурса
preload
для предварительной загрузки шрифтов, но в вашей разметке включите подсказки после ссылки на важные CSS и JavaScript. Сpreload
возникает головоломка с приоритетами, поэтому рассмотрите возможность внедрения элементовrel="preload"
в DOM непосредственно перед внешними блокирующими сценариями. По словам Энди Дэвиса, «ресурсы, внедренные с помощью скрипта, скрыты от браузера до тех пор, пока скрипт не выполнится, и мы можем использовать это поведение, чтобы отложить, когда браузер обнаружит подсказкуpreload
». В противном случае загрузка шрифта обойдется вам в первое время рендеринга.Это хорошая идея, чтобы быть избирательным и выбирать файлы, которые наиболее важны, например, те, которые имеют решающее значение для рендеринга или которые помогут вам избежать видимых и разрушительных перекомпоновок текста. Вообще Зак советует предварительно загружать один-два шрифта каждого семейства — также есть смысл отложить загрузку некоторых шрифтов, если они менее критичны.
Стало довольно распространенным использовать значение
local()
(которое относится к локальному шрифту по имени) при определенииfont-family
шрифтов в правиле@font-face
:/* Warning! Not a good idea! */ @font-face { font-family: Open Sans; src: local('Open Sans Regular'), local('OpenSans-Regular'), url('opensans.woff2') format ('woff2'), url('opensans.woff') format('woff'); }
Идея разумна: некоторые популярные шрифты с открытым исходным кодом, такие как Open Sans, поставляются с предустановленными драйверами или приложениями, поэтому, если шрифт доступен локально, браузеру не нужно загружать веб-шрифт, и он может отображать локальный шрифт. шрифт сразу. Как заметил Брэм Стейн, «хотя локальный шрифт совпадает с названием веб-шрифта, скорее всего , это не тот же самый шрифт . Многие веб-шрифты отличаются от их «настольной» версии. Текст может отображаться по-разному, некоторые символы могут вернуться к другим шрифтам, функции OpenType могут полностью отсутствовать или высота строки может быть другой».
Кроме того, поскольку шрифты со временем развиваются, локально установленная версия может сильно отличаться от веб-шрифта, а символы выглядят совсем иначе. Итак, по словам Брэма, лучше никогда не смешивать локально установленные шрифты и веб-шрифты в правилах
@font-face
. Google Fonts последовал этому примеру, отключивlocal()
в результатах CSS для всех пользователей, кроме запросов Android для Roboto.Никто не любит ждать, пока контент будет отображен. С помощью CSS-дескриптора
font-display
мы можем управлять поведением при загрузке шрифта и сделать содержимое доступным для чтения немедленно (с помощьюfont-display: optional
) или почти сразу (с тайм-аутом 3 с, пока шрифт успешно загружен — с помощьюfont-display: swap
). (Ну, это немного сложнее, чем это.)Однако, если вы хотите свести к минимуму влияние перекомпоновки текста, мы могли бы использовать API загрузки шрифтов (поддерживается во всех современных браузерах). В частности, это означает, что для каждого шрифта мы создадим объект
FontFace
, затем попытаемся получить их все и только потом применить к странице. Таким образом, мы группируем все перерисовки , загружая все шрифты асинхронно, а затем переключаемся с резервных шрифтов на веб-шрифт ровно один раз. Взгляните на объяснение Зака, начиная с 32:15, и фрагмент кода):/* Load two web fonts using JavaScript */ /* Zach Leatherman: https://noti.st/zachleat/KNaZEg/the-five-whys-of-web-font-loading-performance#sWkN4u4 */ // Remove existing @font-face blocks // Create two let font = new FontFace("Noto Serif", /* ... */); let fontBold = new FontFace("Noto Serif, /* ... */); // Load two fonts let fonts = await Promise.all([ font.load(), fontBold.load() ]) // Group repaints and render both fonts at the same time! fonts.forEach(font => documents.fonts.add(font));
/* Load two web fonts using JavaScript */ /* Zach Leatherman: https://noti.st/zachleat/KNaZEg/the-five-whys-of-web-font-loading-performance#sWkN4u4 */ // Remove existing @font-face blocks // Create two let font = new FontFace("Noto Serif", /* ... */); let fontBold = new FontFace("Noto Serif, /* ... */); // Load two fonts let fonts = await Promise.all([ font.load(), fontBold.load() ]) // Group repaints and render both fonts at the same time! fonts.forEach(font => documents.fonts.add(font));
Чтобы инициировать очень раннюю загрузку шрифтов с использованием API загрузки шрифтов, Адриан Бесе предлагает добавить неразрывный пробел
nbsp;
в верхней частиbody
и визуально скройте его с помощьюaria-visibility: hidden
и класса.hidden
:<body class="no-js"> <!-- ... Website content ... --> <div aria-visibility="hidden" class="hidden"> <!-- There is a non-breaking space here --> </div> <script> document.getElementsByTagName("body")[0].classList.remove("no-js"); </script> </body>
<body class="no-js"> <!-- ... Website content ... --> <div aria-visibility="hidden" class="hidden"> <!-- There is a non-breaking space here --> </div> <script> document.getElementsByTagName("body")[0].classList.remove("no-js"); </script> </body>
Это соответствует CSS, в котором разные семейства шрифтов объявлены для разных состояний загрузки, с изменением, инициируемым API загрузки шрифтов после успешной загрузки шрифтов:
body:not(.wf-merriweather--loaded):not(.no-js) { font-family: [fallback-system-font]; /* Fallback font styles */ } .wf-merriweather--loaded, .no-js { font-family: "[web-font-name]"; /* Webfont styles */ } /* Accessible hiding */ .hidden { position: absolute; overflow: hidden; clip: rect(0 0 0 0); height: 1px; width: 1px; margin: -1px; padding: 0; border: 0; }
body:not(.wf-merriweather--loaded):not(.no-js) { font-family: [fallback-system-font]; /* Fallback font styles */ } .wf-merriweather--loaded, .no-js { font-family: "[web-font-name]"; /* Webfont styles */ } /* Accessible hiding */ .hidden { position: absolute; overflow: hidden; clip: rect(0 0 0 0); height: 1px; width: 1px; margin: -1px; padding: 0; border: 0; }
Если вы когда-нибудь задумывались, почему, несмотря на все ваши оптимизации, Lighthouse по-прежнему предлагает исключить ресурсы, блокирующие рендеринг (шрифты), в той же статье Адриан Бесе предлагает несколько методов, чтобы сделать Lighthouse счастливым, а также Gatsby Omni Font Loader, производительный асинхронный шрифт. Плагин загрузки и обработки Flash Of Unstyled Text (FOUT) для Gatsby.
Теперь многие из нас могут использовать CDN или сторонний хост для загрузки веб-шрифтов. В общем, всегда лучше самостоятельно размещать все свои статические ресурсы, если можете, поэтому рассмотрите возможность использования google-webfonts-helper, простого способа самостоятельного размещения шрифтов Google. И если это невозможно, вы можете проксировать файлы шрифтов Google через источник страницы.
Однако стоит отметить, что Google выполняет довольно много работы «из коробки», поэтому серверу может потребоваться небольшая настройка, чтобы избежать задержек ( спасибо, Барри! )
Это очень важно, особенно с учетом того, что начиная с версии Chrome v86 (выпущенной в октябре 2020 г.) межсайтовые ресурсы, такие как шрифты, больше не могут совместно использоваться в одной CDN из-за секционированного кеша браузера. Такое поведение было по умолчанию в Safari в течение многих лет.
Но если это вообще невозможно, есть способ получить максимально быстрые шрифты Google с помощью фрагмента кода Гарри Робертса:
<!-- By Harry Roberts. https://csswizardry.com/2020/05/the-fastest-google-fonts/ - 1. Preemptively warm up the fonts' origin. - 2. Initiate a high-priority, asynchronous fetch for the CSS file. Works in - most modern browsers. - 3. Initiate a low-priority, asynchronous fetch that gets applied to the page - only after it's arrived. Works in all browsers with JavaScript enabled. - 4. In the unlikely event that a visitor has intentionally disabled - JavaScript, fall back to the original method. The good news is that, - although this is a render-blocking request, it can still make use of the - preconnect which makes it marginally faster than the default. --> <!-- [1] --> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <!-- [2] --> <link rel="preload" as="style" href="$CSS&display=swap" /> <!-- [3] --> <link rel="stylesheet" href="$CSS&display=swap" media="print" onload="this.media='all'" /> <!-- [4] --> <noscript> <link rel="stylesheet" href="$CSS&display=swap" /> </noscript>
Стратегия Гарри состоит в том, чтобы сначала заранее прогреть происхождение шрифтов. Затем мы инициируем высокоприоритетную асинхронную выборку файла CSS. После этого мы инициируем низкоприоритетную асинхронную выборку, которая применяется к странице только после ее поступления (с помощью трюка с таблицей стилей печати). Наконец, если JavaScript не поддерживается, мы возвращаемся к исходному методу.
Ах, говоря о Google Fonts: вы можете сократить размер запросов Google Fonts до 90% , объявив только нужные вам символы с помощью
&text
. Кроме того, недавно в Google Fonts была добавлена поддержка отображения шрифтов, так что мы можем использовать ее из коробки.Однако небольшое предостережение. Если вы используете
font-display: optional
, использованиеpreload
может быть неоптимальным, так как это вызовет ранний запрос веб-шрифта (вызывая перегрузку сети , если у вас есть другие ресурсы критического пути, которые необходимо извлечь). Используйтеpreconnect
для более быстрых запросов шрифтов из разных источников, но будьте осторожны сpreload
загрузкой, так как предварительная загрузка шрифтов из другого источника вызовет конкуренцию в сети. Все эти приемы описаны в рецептах загрузки веб-шрифтов Зака.С другой стороны, может быть хорошей идеей отказаться от веб-шрифтов (или, по крайней мере, рендеринга второго этапа), если пользователь включил функцию «Уменьшение движения» в настройках специальных возможностей или выбрал режим экономии данных (см. заголовок «
Save-Data
»). , или когда у пользователя медленное подключение (через Network Information API).Мы также можем использовать медиа-запрос
prefers-reduced-data
CSS, чтобы не определять объявления шрифтов, если пользователь выбрал режим сохранения данных (есть и другие варианты использования). Медиа-запрос в основном раскрывает, включен или выключен заголовок запросаSave-Data
из HTTP-расширения Client Hint, чтобы разрешить использование с CSS. В настоящее время поддерживается только в Chrome и Edge.Метрики? Чтобы измерить производительность загрузки веб-шрифтов, рассмотрите метрику « Видимый весь текст » (момент, когда все шрифты загружены и весь контент отображается в веб-шрифтах), время до реального курсива, а также счетчик перекомпоновки веб-шрифтов после первого рендеринга. Очевидно, что чем ниже обе метрики, тем выше производительность.
А как насчет вариативных шрифтов , спросите вы? Важно отметить, что вариативные шрифты могут потребовать значительного внимания к производительности. Они дают нам гораздо более широкое дизайнерское пространство для выбора типографики, но это происходит за счет одного последовательного запроса, а не нескольких запросов отдельных файлов.
В то время как вариативные шрифты резко уменьшают общий объединенный размер файлов шрифтов, один запрос может быть медленным, блокируя отрисовку всего содержимого на странице. Таким образом, подмножество и разделение шрифта на наборы символов по-прежнему имеют значение. С хорошей стороны, однако, с переменным шрифтом мы получим ровно одно переформатирование по умолчанию, поэтому для группировки перерисовок не потребуется JavaScript.
Итак, что тогда может сделать пуленепробиваемую стратегию загрузки веб-шрифтов ? Подмножьте шрифты и подготовьте их к двухэтапному рендерингу, объявите их с помощью дескриптора
font-display
шрифтов, используйте API загрузки шрифтов для группировки перерисовок и сохранения шрифтов в постоянном кэше сервисного работника. При первом посещении введите предварительную загрузку скриптов непосредственно перед блокировкой внешних скриптов. При необходимости вы можете вернуться к Font Face Observer Брэма Штейна. А если вам интересно измерить производительность загрузки шрифтов, Андреас Маршке исследует отслеживание производительности с помощью Font API и UserTiming API.Наконец, не забудьте включить
unicode-range
, чтобы разбить большой шрифт на более мелкие шрифты для конкретного языка, и использовать сопоставитель стиля шрифта Моники Динкулеску, чтобы свести к минимуму резкое изменение макета из-за несоответствия размеров между запасным и исходным шрифтами. веб-шрифты.В качестве альтернативы, чтобы эмулировать веб-шрифт для резервного шрифта, мы можем использовать дескрипторы @font-face для переопределения метрик шрифта (демонстрация, включена в Chrome 87). (Обратите внимание, что настройки сложны со сложными стеками шрифтов.)
Будущее выглядит светлым? С прогрессивным обогащением шрифта в конечном итоге мы сможем «загружать только необходимую часть шрифта на любой данной странице, а для последующих запросов на этот шрифт динамически« исправлять »исходную загрузку с дополнительными наборами глифов по мере необходимости на последующей странице. просмотров», как объясняет Джейсон Паменталь. Демо-версия Incremental Transfer уже доступна, и работа над ней продолжается.
Оптимизация сборки
- Определили ли мы наши приоритеты?
Это хорошая идея, чтобы знать, с чем вы имеете дело в первую очередь. Проведите инвентаризацию всех ваших ресурсов (JavaScript, изображения, шрифты, сторонние скрипты и «дорогие» модули на странице, такие как карусели, сложная инфографика и мультимедийный контент), и разбейте их на группы.Настройте электронную таблицу . Определите основные возможности для устаревших браузеров (т. е. полностью доступный основной контент), расширенные возможности для поддерживающих браузеров (т. е. расширенные, полные возможности) и дополнительные функции (ресурсы, которые не являются абсолютно необходимыми и могут загружаться отложенно, например веб-шрифты, ненужные стили, сценарии карусели, видеоплееры, виджеты социальных сетей, большие изображения). Несколько лет назад мы опубликовали статью «Улучшение производительности Smashing Magazine», в которой подробно описывается этот подход.
При оптимизации производительности нам необходимо учитывать наши приоритеты. Немедленно загрузите основные возможности , затем улучшения , а затем дополнительные функции .
- Используете ли вы нативные модули JavaScript в продакшене?
Помните старую добрую технику «перерезать горчицу», чтобы отправить базовый опыт в устаревшие браузеры и расширенный опыт в современные браузеры? Обновленный вариант метода может использовать ES2017+<script type="module">
, также известный как шаблон module/nomodule (также представленный Джереми Вагнером как дифференциальное обслуживание ).Идея состоит в том, чтобы скомпилировать и обслуживать два отдельных пакета JavaScript : «обычная» сборка, та, что с Babel-преобразованиями и полифиллами, и обслуживать их только для устаревших браузеров, которым они действительно нужны, и еще один пакет (с той же функциональностью), который не имеет преобразований или полифиллы.
В результате мы помогаем уменьшить блокировку основного потока за счет уменьшения количества сценариев, которые должен обрабатывать браузер. Джереми Вагнер опубликовал исчерпывающую статью о дифференциальном обслуживании и о том, как настроить его в конвейере сборки, от настройки Babel до настроек, которые вам нужно будет внести в Webpack, а также о преимуществах выполнения всей этой работы.
Скрипты встроенных модулей JavaScript по умолчанию откладываются, поэтому, пока происходит синтаксический анализ HTML, браузер загружает основной модуль.
Тем не менее одно предупреждение: шаблон модуль/номодуль может иметь неприятные последствия для некоторых клиентов, поэтому вы можете рассмотреть обходной путь: менее рискованный шаблон дифференциального обслуживания Джереми, который, однако, обходит сканер предварительной загрузки, что может повлиять на производительность способами, которые не могли бы быть. предвидеть. ( спасибо, Джереми! )
На самом деле, Rollup поддерживает модули в качестве выходного формата, поэтому мы можем как объединять код, так и развертывать модули в рабочей среде. Parcel имеет поддержку модулей в Parcel 2. Для Webpack module-nomodule-plugin автоматизирует генерацию скриптов модуля/номодуля.
Примечание . Стоит отметить, что одного обнаружения функций недостаточно для принятия обоснованного решения о том, какую полезную нагрузку отправлять в этот браузер. Само по себе мы не можем вывести возможности устройства из версии браузера. Например, недорогие телефоны Android в развивающихся странах в основном работают под управлением Chrome и будут сокращать горчицу, несмотря на ограниченные возможности памяти и процессора.
В конце концов, используя заголовок Device Memory Client Hints, мы сможем более надежно нацеливаться на недорогие устройства. На момент написания заголовок поддерживается только в Blink (в основном он касается клиентских подсказок). Поскольку Device Memory также имеет JavaScript API, который доступен в Chrome, одним из вариантов может быть функция обнаружения на основе API и возврат к шаблону module/nomodule, если он не поддерживается ( спасибо, Йоав! ).
- Используете ли вы встряхивание дерева, подъем области видимости и разделение кода?
Tree-shaking — это способ очистить ваш процесс сборки, включив только тот код, который фактически используется в производстве, и исключив неиспользуемый импорт в Webpack. С Webpack и Rollup у нас также есть подъем области, который позволяет обоим инструментам определять, где цепочкуimport
можно сгладить и преобразовать в одну встроенную функцию без ущерба для кода. С Webpack мы также можем использовать JSON Tree Shaking.Разделение кода — еще одна функция Webpack, которая разбивает вашу кодовую базу на «фрагменты», которые загружаются по запросу. Не весь код JavaScript нужно скачивать, парсить и компилировать сразу. Как только вы определите точки разделения в своем коде, Webpack может позаботиться о зависимостях и выходных файлах. Это позволяет вам сохранить первоначальную загрузку небольшой и запрашивать код по требованию, когда его запрашивает приложение. У Александра Кондрова есть фантастическое введение в разделение кода с помощью Webpack и React.
Рассмотрите возможность использования плагина preload-webpack-plugin, который принимает маршруты, разделенные кодом, а затем предлагает браузеру предварительно загрузить их с помощью
<link rel="preload">
или<link rel="prefetch">
. Встроенные директивы Webpack также дают некоторый контроль надpreload
/prefetch
. (Остерегайтесь проблем с расстановкой приоритетов.)Где определить точки разделения? Отслеживая, какие фрагменты CSS/JavaScript используются, а какие нет. Умар Ханса объясняет, как вы можете использовать покрытие кода от Devtools для достижения этой цели.
При работе с одностраничными приложениями нам нужно некоторое время для инициализации приложения, прежде чем мы сможем отобразить страницу. Для вашей настройки потребуется ваше индивидуальное решение, но вы можете следить за модулями и методами, чтобы ускорить начальное время рендеринга. Например, вот как отлаживать производительность React и устранять распространенные проблемы с производительностью React, а вот как повысить производительность в Angular. Как правило, большинство проблем с производительностью возникает при начальной загрузке приложения.
Итак, каков наилучший способ агрессивного, но не слишком агрессивного разделения кода? По словам Фила Уолтона, «в дополнение к разделению кода с помощью динамического импорта [мы могли бы] также использовать разделение кода на уровне пакета , где каждый импортированный модуль узла помещается в фрагмент на основе имени его пакета». Фил также предоставляет учебник о том, как его построить.
- Можем ли мы улучшить вывод Webpack?
Поскольку Webpack часто считается загадочным, существует множество подключаемых модулей Webpack, которые могут пригодиться для дальнейшего уменьшения производительности Webpack. Ниже приведены некоторые из наиболее неясных из них, которые могут потребовать немного больше внимания.Один из интересных исходит из ветки Ивана Акулова. Представьте, что у вас есть функция, которую вы вызываете один раз, сохраняете ее результат в переменной и затем не используете эту переменную. Tree-shaking удалит переменную, но не функцию, потому что она может использоваться иначе. Однако, если функция нигде не используется, вы можете удалить ее. Для этого добавьте к вызову функции
/*#__PURE__*/
, который поддерживается Uglify и Terser — готово!Вот некоторые из других инструментов, которые рекомендует Иван:
- purgecss-webpack-plugin удаляет неиспользуемые классы, особенно если вы используете Bootstrap или Tailwind.
- Включить
optimization.splitChunks: 'all'
с помощью плагина split-chunks. Это заставит веб-пакет автоматически разделить код ваших входных пакетов для лучшего кэширования. - Задайте для
optimization.runtimeChunk: true
. Это переместит среду выполнения веб-пакета в отдельный фрагмент, а также улучшит кеширование. - google-fonts-webpack-plugin загружает файлы шрифтов, чтобы вы могли обслуживать их со своего сервера.
- workbox-webpack-plugin позволяет создать сервис-воркер с настройкой предварительного кэширования для всех ваших ресурсов веб-пакета. Кроме того, ознакомьтесь с пакетами Service Worker, исчерпывающим руководством по модулям, которые можно сразу применить. Или используйте preload-webpack-plugin для создания
preload
/prefetch
для всех фрагментов JavaScript. - speed-measure-webpack-plugin измеряет скорость сборки вашего веб-пакета, предоставляя информацию о том, какие этапы процесса сборки занимают больше всего времени.
- дубликат-пакет-проверки-вебпак-плагин предупреждает, когда ваш пакет содержит несколько версий одного и того же пакета.
- Используйте изоляцию области действия и динамически сокращайте имена классов CSS во время компиляции.
- Можно ли разгрузить JavaScript в Web Worker?
Чтобы уменьшить негативное влияние на Time-to-Interactive, может быть хорошей идеей рассмотреть возможность разгрузки тяжелого JavaScript в Web Worker.По мере роста кодовой базы будут появляться узкие места в производительности пользовательского интерфейса, что замедляет работу пользователя. Это потому, что операции DOM выполняются вместе с вашим JavaScript в основном потоке. С помощью веб-воркеров мы можем переместить эти дорогостоящие операции в фоновый процесс, работающий в другом потоке. Типичными вариантами использования веб-воркеров являются предварительная выборка данных и прогрессивные веб-приложения для загрузки и сохранения некоторых данных заранее, чтобы вы могли использовать их позже, когда это необходимо. И вы можете использовать Comlink для оптимизации связи между главной страницей и воркером. Еще есть над чем поработать, но мы к этому идем.
Есть несколько интересных тематических исследований, посвященных веб-воркерам, которые демонстрируют различные подходы к перемещению фреймворка и логики приложений в веб-воркеры. Вывод: в общем-то проблемы еще есть, но уже есть хорошие варианты использования ( спасибо, Иван Акулов! ).
Начиная с Chrome 80, появился новый режим для веб-работников с преимуществами производительности модулей JavaScript, который называется рабочими модулями. Мы можем изменить загрузку и выполнение скрипта, чтобы он соответствовал
script type="module"
, плюс мы также можем использовать динамический импорт для ленивой загрузки кода, не блокируя выполнение воркера.С чего начать? Вот несколько ресурсов, на которые стоит обратить внимание:
- Surma опубликовал отличное руководство о том, как запускать JavaScript вне основного потока браузера, а также о том, когда следует использовать Web Workers?
- Кроме того, проверьте разговор Сурма об архитектуре вне основного потока.
- В книге «В поисках гарантии отзывчивости» Шубхи Пэникер и Джейсон Миллер подробно рассказывается о том, как использовать веб-воркеры и когда их следует избегать.
- Как не мешать пользователям: меньше мусора с помощью Web Workers освещает полезные шаблоны для работы с Web Workers, эффективные способы взаимодействия между worker, выполнение сложной обработки данных вне основного потока, а также их тестирование и отладку.
- Workerize позволяет переместить модуль в Web Worker, автоматически отражая экспортированные функции как асинхронные прокси.
- Если вы используете Webpack, вы можете использовать workerize-loader. Кроме того, вы также можете использовать рабочий плагин.
Обратите внимание, что веб-воркеры не имеют доступа к DOM, потому что DOM не является «потокобезопасным», а код, который они выполняют, должен содержаться в отдельном файле.
- Можете ли вы разгрузить «горячие пути» для WebAssembly?
Мы могли бы переложить тяжелые вычислительные задачи на WebAssembly ( WASM ), формат двоичных инструкций, разработанный как переносимая цель для компиляции языков высокого уровня, таких как C/C++/Rust. Его браузерная поддержка замечательна, и в последнее время он стал жизнеспособным, поскольку вызовы функций между JavaScript и WASM становятся быстрее. Кроме того, он поддерживается даже в пограничном облаке Fastly.Конечно, WebAssembly не должен заменять JavaScript, но он может дополнить его в тех случаях, когда вы заметили перегрузку процессора. Для большинства веб-приложений больше подходит JavaScript, а WebAssembly лучше всего использовать для ресурсоемких веб-приложений , таких как игры.
Если вы хотите узнать больше о WebAssembly:
- Лин Кларк написал обширную серию статей для WebAssembly, а Милица Михайлия дает общий обзор того, как запускать нативный код в браузере, почему вы можете захотеть это сделать и что все это значит для JavaScript и будущего веб-разработки.
- Как мы использовали WebAssembly для ускорения работы нашего веб-приложения в 20 раз (пример из практики) освещает пример того, как медленные вычисления JavaScript были заменены скомпилированным WebAssembly, что привело к значительному повышению производительности.
- Патрик Хаманн говорил о растущей роли WebAssembly, и он развенчивает некоторые мифы о WebAssembly, исследует его проблемы, и сегодня мы можем использовать его практически в приложениях.
- Google Codelabs предлагает Введение в WebAssembly, 60-минутный курс, в котором вы узнаете, как взять нативный код — на C и скомпилировать его в WebAssembly, а затем вызвать его непосредственно из JavaScript.
- Алекс Данило рассказал о WebAssembly и о том, как он работает, в своем выступлении на Google I/O. Кроме того, Бенедек Гаджи поделился практическим примером WebAssembly, в частности, как команда использует его в качестве формата вывода своей кодовой базы C++ для iOS, Android и веб-сайта.
Все еще не знаете, когда использовать Web Workers, Web Assembly, потоки или, возможно, WebGL JavaScript API для доступа к GPU? Ускорение JavaScript — это краткое, но полезное руководство, объясняющее, когда что использовать и почему, а также с удобной блок-схемой и множеством полезных ресурсов.
- Предоставляем ли мы устаревший код только устаревшим браузерам?
Поскольку ES2017 замечательно поддерживается современными браузерами, мы можем использоватьbabelEsmPlugin
только для переноса функций ES2017+, которые не поддерживаются современными браузерами, на которые вы ориентируетесь.Хуссейн Джирде и Джейсон Миллер недавно опубликовали исчерпывающее руководство по транспиляции и обслуживанию современного и устаревшего JavaScript, подробно рассказывая о том, как заставить его работать с Webpack и Rollup, а также о необходимых инструментах. Вы также можете оценить, сколько JavaScript вы можете сократить на своем сайте или в наборах приложений.
Модули JavaScript поддерживаются во всех основных браузерах, поэтому используйте
script type="module"
, чтобы позволить браузерам с поддержкой модуля ES загружать файл, в то время как старые браузеры могли загружать устаревшие сборки соscript nomodule
.В наши дни мы можем писать JavaScript на основе модулей, который изначально запускается в браузере, без транспиляторов или упаковщиков. Заголовок
<link rel="modulepreload">
позволяет инициировать раннюю (и высокоприоритетную) загрузку скриптов модуля. По сути, это отличный способ помочь в максимальном использовании пропускной способности, сообщая браузеру о том, что ему нужно получить, чтобы он не застрял ни в чем во время этих длинных циклов. Кроме того, Джейк Арчибальд опубликовал подробную статью с подводными камнями и вещами, о которых следует помнить при работе с модулями ES, которые стоит прочитать.
- Выявляйте и переписывайте устаревший код с помощью постепенного разделения .
Долгоживущие проекты имеют тенденцию собирать пыль и устаревший код. Пересмотрите свои зависимости и оцените, сколько времени потребуется на рефакторинг или переписывание устаревшего кода, который в последнее время вызывал проблемы. Конечно, это всегда большое мероприятие, но как только вы узнаете о влиянии устаревшего кода, вы можете начать с постепенного разделения.Во-первых, настройте метрики, которые отслеживают, остается ли соотношение вызовов устаревшего кода постоянным или снижается, а не растет. Публично отговаривайте команду от использования библиотеки и убедитесь, что ваш CI предупреждает разработчиков, если он используется в запросах на вытягивание. полифилы могут помочь перейти от устаревшего кода к переписанной кодовой базе, использующей стандартные функции браузера.
- Определите и удалите неиспользуемые CSS/JS .
Покрытие кода CSS и JavaScript в Chrome позволяет узнать, какой код был выполнен/применен, а какой нет. Вы можете начать запись покрытия, выполнить действия на странице, а затем изучить результаты покрытия кода. Как только вы обнаружите неиспользуемый код, найдите эти модули и выполните ленивую загрузку с помощьюimport()
(см. весь поток). Затем повторите профиль покрытия и убедитесь, что теперь он отправляет меньше кода при начальной загрузке.Вы можете использовать Puppeteer для программного сбора покрытия кода. Chrome также позволяет экспортировать результаты покрытия кода. Как заметил Энди Дэвис, вам может понадобиться собрать данные о покрытии кода как для современных, так и для устаревших браузеров.
Есть много других вариантов использования и инструментов для Puppetter, которые могут потребовать немного больше внимания:
- Варианты использования Puppeteer, такие как, например, автоматическое визуальное сравнение или мониторинг неиспользуемого CSS при каждой сборке,
- Рецепты веб-производительности с Puppeteer,
- Полезные инструменты для записи и создания сценариев Pupeeteer и Playwright,
- Кроме того, вы даже можете записывать тесты прямо в DevTools,
- Всесторонний обзор Puppeteer от Нитая Нимана с примерами и вариантами использования.
Кроме того, purgecss, UnCSS и Helium могут помочь вам удалить неиспользуемые стили из CSS. И если вы не уверены, что где-то используется подозрительный фрагмент кода, вы можете последовать совету Гарри Робертса: создайте прозрачный GIF размером 1×1px для определенного класса и поместите его в каталог
dead/
, например,/assets/img/dead/comments.gif
.После этого вы устанавливаете это конкретное изображение в качестве фона для соответствующего селектора в вашем CSS, сидите сложа руки и ждете несколько месяцев, если файл появится в ваших журналах. Если записей нет, значит, ни у кого этот устаревший компонент не отображался на экране: вы, вероятно, можете удалить его целиком.
Для отдела I-feel-adventure вы можете даже автоматизировать сбор неиспользуемых CSS через набор страниц, отслеживая DevTools с помощью DevTools.
- Сократите размер ваших пакетов JavaScript.
Как заметила Эдди Османи, велика вероятность, что вы отправляете полные библиотеки JavaScript, когда вам нужна только часть, вместе с устаревшими полифиллами для браузеров, которым они не нужны, или просто дублируете код. Чтобы избежать накладных расходов, рассмотрите возможность использования оптимизации webpack-libs, которая удаляет неиспользуемые методы и полифиллы в процессе сборки.Проверяйте и просматривайте полифиллы , которые вы отправляете в устаревшие и современные браузеры, и относитесь к ним более стратегически. Взгляните на polyfill.io, службу, которая принимает запрос на набор функций браузера и возвращает только те полифиллы, которые необходимы запрашивающему браузеру.
Добавьте аудит пакетов в свой обычный рабочий процесс. Могут быть некоторые облегченные альтернативы тяжелым библиотекам, которые вы добавили много лет назад, например, Moment.js (сейчас снят с производства) можно заменить на:
- Собственный API интернационализации,
- Day.js со знакомым API Moment.js и шаблонами,
- дата-fns или
- Люксон.
- Вы также можете использовать Skypack Discover, который сочетает в себе проверенные людьми рекомендации пакетов с поиском, ориентированным на качество.
Исследование Бенедикта Ротша показало, что переход с Moment.js на date-fns может сократить примерно 300 мс для First Paint на 3G и недорогих мобильных телефонах.
Что касается аудита пакетов, Bundlephobia может помочь определить стоимость добавления пакета npm в ваш пакет. size-limit расширяет базовую проверку размера пакета, добавляя сведения о времени выполнения JavaScript. Вы даже можете интегрировать эти затраты с индивидуальным аудитом Lighthouse. Это касается и фреймворков. При удалении или обрезке Vue MDC Adapter (Material Components for Vue) стили уменьшаются со 194 КБ до 10 КБ.
Есть много дополнительных инструментов, которые помогут вам принять обоснованное решение о влиянии ваших зависимостей и жизнеспособных альтернатив:
- webpack-bundle-analyzer
- Обозреватель исходных карт
- Бандл Бадди
- связки фобия
- Анализ Webpack показывает, почему конкретный модуль включен в комплект.
- bundle-wizard также строит карту зависимостей для всей страницы.
- Плагин размера Webpack
- Стоимость импорта визуального кода
В качестве альтернативы отправке всего фреймворка вы можете обрезать свой фреймворк и скомпилировать его в необработанный пакет JavaScript , который не требует дополнительного кода. Это делает Svelte, как и плагин Rawact Babel, который транспилирует компоненты React.js в нативные операции DOM во время сборки. Почему? Ну, как объясняют сопровождающие, «react-dom включает в себя код для каждого возможного компонента/элемента HTML, который может быть отрисован, включая код для инкрементного рендеринга, планирования, обработки событий и т. д. Но есть приложения, которым не нужны все эти функции (на начальном этапе загрузка страницы). Для таких приложений может иметь смысл использовать собственные операции DOM для создания интерактивного пользовательского интерфейса».
- Используем ли мы частичную гидратацию?
Учитывая количество JavaScript, используемого в приложениях, нам нужно выяснить, как отправлять клиенту как можно меньше. Один из способов сделать это — и мы уже кратко рассмотрели его — частичное увлажнение. Идея довольно проста: вместо того, чтобы выполнять SSR и затем отправлять все приложение клиенту, клиенту будут отправляться только небольшие фрагменты JavaScript приложения, а затем обрабатываться. Мы можем думать об этом как о нескольких крошечных приложениях React с несколькими корнями рендеринга на статичном веб-сайте.В статье «Случай частичной гидратации (с Next и Preact)» Лукас Бомбах объясняет, как команда Welt.de, одного из новостных агентств в Германии, добилась лучших результатов при частичной гидратации. Вы также можете проверить репозиторий следующего сверхпроизводительного GitHub с пояснениями и фрагментами кода.
Также можно рассмотреть альтернативные варианты:
- частичное увлажнение Preact и Eleventy,
- прогрессивная гидратация в репозитории React GitHub,
- ленивая гидратация в Vue.js (репозиторий GitHub),
- Импорт шаблона взаимодействия для ленивой загрузки некритических ресурсов (например, компонентов, встраивания), когда пользователь взаимодействует с пользовательским интерфейсом, которому это необходимо.
Джейсон Миллер опубликовал рабочие демонстрации о том, как можно реализовать прогрессивную гидратацию с помощью React, так что вы можете сразу их использовать: демонстрация 1, демонстрация 2, демонстрация 3 (также доступны на GitHub). Кроме того, вы можете заглянуть в библиотеку react-prerendered-component.
- Оптимизировали ли мы стратегию для React/SPA?
Боретесь с производительностью в своем одностраничном приложении? Джереми Вагнер исследовал влияние производительности фреймворка на стороне клиента на различных устройствах, выделив некоторые последствия и рекомендации, о которых мы, возможно, хотели бы знать при их использовании.В результате вот стратегия SPA, которую Джереми предлагает использовать для платформы React (но она не должна существенно измениться для других платформ):
- Рефакторинг компонентов с состоянием как компонентов без состояния, когда это возможно.
- По возможности выполняйте предварительную визуализацию компонентов без состояния, чтобы свести к минимуму время отклика сервера. Рендерить только на сервере.
- Для компонентов с отслеживанием состояния с простой интерактивностью рассмотрите возможность предварительного рендеринга или серверного рендеринга этого компонента и замените его интерактивность независимыми от фреймворка обработчиками событий .
- Если вам необходимо гидратировать компоненты с отслеживанием состояния на клиенте, используйте ленивую гидратацию для видимости или взаимодействия.
- Для компонентов с ленивой гидратацией запланируйте их гидратацию во время простоя основного потока с помощью
requestIdleCallback
.
Есть несколько других стратегий, которые вы, возможно, захотите применить или пересмотреть:
- Вопросы производительности для CSS-in-JS в приложениях React
- Уменьшите размер пакета Next.js, загружая полифиллы только при необходимости, используя динамический импорт и ленивую гидратацию.
- Секреты JavaScript: рассказ о React, оптимизации производительности и многопоточности, длинная серия из 7 статей, посвященная решению проблем пользовательского интерфейса с помощью React,
- Как измерить производительность React и как профилировать приложения React.
- Создание мобильной веб-анимации в React, фантастическое выступление Алекса Холачека, а также слайды и репозиторий GitHub ( спасибо за совет, Эдди! ).
- webpack-libs-optimizations — фантастическое репозиторий GitHub с множеством полезных оптимизаций, связанных с производительностью Webpack. Поддерживает Иван Акулов.
- Улучшения производительности React в Notion, руководство Ивана Акулова о том, как повысить производительность в React, с множеством полезных советов, которые сделают приложение примерно на 30% быстрее.
- Плагин React Refresh Webpack (экспериментальный) обеспечивает горячую перезагрузку, которая сохраняет состояние компонента, а также поддерживает хуки и функциональные компоненты.
- Остерегайтесь компонентов React Server с нулевым размером пакета — нового предлагаемого типа компонентов, который не повлияет на размер пакета. В настоящее время проект находится в разработке, но мы очень ценим любые отзывы сообщества (прекрасное объяснение от Софи Альперт).
- Используете ли вы прогнозную предварительную выборку для фрагментов JavaScript?
Мы могли бы использовать эвристику, чтобы решить, когда предварительно загружать куски JavaScript. Guess.js — это набор инструментов и библиотек, которые используют данные Google Analytics для определения того, какую страницу пользователь, скорее всего, посетит следующей с данной страницы. На основе шаблонов пользовательской навигации, собранных из Google Analytics или других источников, Guess.js строит модель машинного обучения для прогнозирования и предварительной выборки JavaScript, который потребуется на каждой последующей странице.Таким образом, каждый интерактивный элемент получает оценку вероятности вовлечения, и на основе этой оценки клиентский сценарий решает заблаговременно получить ресурс. Вы можете интегрировать эту технику в свое приложение Next.js, Angular и React, и есть плагин Webpack, который также автоматизирует процесс установки.
Очевидно, что вы можете подтолкнуть браузер к потреблению ненужных данных и предварительной выборке нежелательных страниц, поэтому рекомендуется быть достаточно консервативным в отношении количества предварительно выбранных запросов. Хорошим вариантом использования будет предварительная выборка сценариев проверки, необходимых при оформлении заказа, или спекулятивная предварительная выборка, когда критический призыв к действию появляется в области просмотра.
Нужно что-то менее сложное? DNStradamus выполняет предварительную выборку DNS для исходящих ссылок по мере их появления в окне просмотра. Quicklink, InstantClick и Instant.page — это небольшие библиотеки, которые автоматически выполняют предварительную выборку ссылок в области просмотра во время простоя, пытаясь ускорить загрузку навигации на следующей странице. Quicklink позволяет предварительно загружать маршруты React Router и Javascript; кроме того, он учитывает данные, поэтому он не выполняет предварительную выборку в 2G или если
Data-Saver
. Так же, как и Instant.page, если режим настроен на использование предварительной выборки области просмотра (по умолчанию).Если вы хотите подробно изучить науку прогнозной предварительной выборки, у Дивьи Тагтачян есть отличный доклад «Искусство прогнозной предварительной выборки», в котором рассматриваются все варианты от начала до конца.
- Воспользуйтесь оптимизацией для вашего целевого движка JavaScript.
Изучите, какие движки JavaScript доминируют в вашей пользовательской базе, а затем изучите способы их оптимизации. Например, при оптимизации для V8, который используется в браузерах Blink, среде выполнения Node.js и Electron, используйте потоковую передачу скриптов для монолитных скриптов.Потоковая передача сценариев позволяет анализировать
async
илиdefer scripts
в отдельном фоновом потоке после начала загрузки, поэтому в некоторых случаях время загрузки страницы сокращается до 10%. Практически используйте<script defer>
в<head>
, чтобы браузеры могли заранее обнаружить ресурс, а затем проанализировать его в фоновом потоке.Предостережение : Opera Mini не поддерживает отсрочку скрипта, поэтому, если вы разрабатываете для Индии или Африки,
defer
будет проигнорирована, что приведет к блокировке рендеринга до тех пор, пока скрипт не будет оценен (спасибо, Джереми!) .Вы также можете подключиться к кэшированию кода V8, отделив библиотеки от кода, использующего их, или наоборот, объединить библиотеки и их использование в один скрипт, сгруппировать небольшие файлы вместе и избежать встроенных скриптов. Или, возможно, даже использовать v8-compile-cache.
Когда дело доходит до JavaScript в целом, есть несколько правил, о которых стоит помнить:
- Концепции чистого кода для JavaScript, большая коллекция шаблонов для написания читаемого, многократно используемого и рефакторингового кода.
- Вы можете сжимать данные из JavaScript с помощью CompressionStream API, например, с помощью gzip перед загрузкой данных (Chrome 80+).
- Утечки памяти в отдельном окне и Устранение утечек памяти в веб-приложениях — подробные руководства о том, как найти и исправить сложные утечки памяти JavaScript. Кроме того, вы можете использовать queryObjects(SomeConstructor) из консоли DevTools ( спасибо, Матиас! ).
- Повторный экспорт вреден для загрузки и производительности во время выполнения, и отказ от него может помочь значительно уменьшить размер пакета.
- Мы можем улучшить производительность прокрутки с помощью пассивных прослушивателей событий, установив флаг в параметре
options
. Таким образом, браузеры могут прокручивать страницу сразу, а не после того, как слушатель закончит. (через Кейси Басков). - Если у вас есть слушатели
scroll
илиtouch*
, передайтеpassivepassive: true
в addEventListener. Это сообщает браузеру, что вы не планируете вызыватьevent.preventDefault()
внутри, поэтому он может оптимизировать способ обработки этих событий. (через Ивана Акулова) - Мы можем улучшить планирование JavaScript с помощью isInputPending(), нового API, который пытается преодолеть разрыв между загрузкой и реагированием с помощью концепций прерываний для пользовательского ввода в Интернете и позволяет JavaScript проверять ввод, не уступая браузер.
- Вы также можете автоматически удалить прослушиватель событий после его выполнения.
- Firefox недавно выпустил Warp, значительное обновление SpiderMonkey (поставляется в Firefox 83), Baseline Interpreter, а также доступно несколько стратегий JIT-оптимизации.
- Всегда предпочитайте самостоятельно размещать сторонние ресурсы.
Опять же, по умолчанию размещайте свои статические ресурсы самостоятельно. Принято считать, что если многие сайты используют один и тот же общедоступный CDN и одну и ту же версию библиотеки JavaScript или веб-шрифта, то посетители попадут на наш сайт с уже кэшированными в браузере скриптами и шрифтами, что значительно ускорит их работу. . Однако это очень маловероятно.Из соображений безопасности, чтобы избежать «отпечатков пальцев», браузеры внедряют секционированное кэширование, которое было введено в Safari еще в 2013 году и в Chrome в прошлом году. Таким образом, если два сайта указывают на один и тот же URL-адрес стороннего ресурса, код загружается один раз для каждого домена , а кэш «изолируется» для этого домена из-за последствий для конфиденциальности ( спасибо, Дэвид Калхун! ). Следовательно, использование общедоступной CDN не приведет автоматически к повышению производительности.
Кроме того, стоит отметить, что ресурсы не живут в кеше браузера так долго, как мы могли бы ожидать, и собственные ресурсы с большей вероятностью останутся в кеше, чем сторонние ресурсы. Таким образом, самостоятельный хостинг обычно более надежен и безопасен, а также обеспечивает лучшую производительность.
- Ограничьте влияние сторонних скриптов.
Со всеми оптимизациями производительности мы часто не можем контролировать сторонние сценарии, исходящие из бизнес-требований. Показатели сторонних скриптов не зависят от взаимодействия с конечным пользователем, поэтому слишком часто один единственный скрипт вызывает длинный шлейф неприятных сторонних скриптов, тем самым сводя на нет усилия по повышению производительности. Чтобы сдержать и смягчить потери производительности, которые несут с собой эти сценарии, недостаточно просто отложить их загрузку и выполнение и разогреть соединения с помощью подсказок ресурсов, т.е.dns-prefetch
илиpreconnect
.В настоящее время 57% всего времени выполнения кода JavaScript тратится на сторонний код. Средний мобильный сайт обращается к 12 сторонним доменам , при этом в среднем 37 различных запросов (или около 3 запросов к каждой третьей стороне).
Кроме того, эти третьи стороны часто приглашают сторонние сценарии присоединиться к ним, что в конечном итоге приводит к огромному узким местам в производительности, иногда доходя до сторонних сценариев на странице. Поэтому регулярный аудит ваших зависимостей и менеджеров тегов может принести дорогостоящие сюрпризы.
Еще одна проблема, как объяснил Йоав Вайс в своем выступлении о сторонних сценариях, заключается в том, что во многих случаях эти сценарии загружают ресурсы, которые являются динамическими. Ресурсы меняются между загрузками страниц, поэтому мы не обязательно знаем, с каких хостов будут загружены ресурсы и какими ресурсами они будут.
Отсрочка, как показано выше, может быть только началом, поскольку сторонние скрипты также крадут пропускную способность и процессорное время вашего приложения. Мы могли бы быть немного более агрессивными и загружать их только тогда, когда наше приложение инициализировано.
/* Before */ const App = () => { return <div> <script> window.dataLayer = window.dataLayer || []; function gtag(){...} gtg('js', new Date()); </script> </div> } /* After */ const App = () => { const[isRendered, setRendered] = useState(false); useEffect(() => setRendered(true)); return <div> {isRendered ? <script> window.dataLayer = window.dataLayer || []; function gtag(){...} gtg('js', new Date()); </script> : null} </div> }
В фантастическом посте «Уменьшение влияния сторонних тегов на скорость сайта» Энди Дэвис исследует стратегию минимизации влияния сторонних тегов — от определения их затрат до снижения их влияния.
По словам Энди, теги влияют на скорость сайта двумя способами: они конкурируют за пропускную способность сети и время обработки на устройствах посетителей, и в зависимости от того, как они реализованы, они также могут задерживать синтаксический анализ HTML. Итак, первый шаг — определить влияние третьих сторон, протестировав сайт со сценариями и без них с помощью WebPageTest. С помощью карты запросов Саймона Херна мы также можем визуализировать третьих лиц на странице вместе с подробной информацией об их размере, типе и причинах их загрузки.
Предпочтительно размещать самостоятельно и использовать одно имя хоста, но также использовать карту запросов, чтобы выявлять сторонние вызовы и определять, когда сценарии изменяются. Вы можете использовать подход Гарри Робертса для аудита третьих сторон и создавать электронные таблицы, подобные этой (также проверьте рабочий процесс аудита Гарри).
После этого мы можем исследовать облегченные альтернативы существующим сценариям и постепенно заменять дубликаты и основных виновников более легкими вариантами. Возможно, некоторые из скриптов можно было бы заменить их резервным пикселем отслеживания вместо полного тега.
Если это нецелесообразно, мы можем, по крайней мере, лениво загружать сторонние ресурсы с помощью фасадов, то есть статических элементов, которые выглядят похожими на фактически встроенные сторонние ресурсы, но не являются функциональными и, следовательно, гораздо менее требовательны к загрузке страницы. Таким образом, хитрость заключается в том, чтобы загружать фактическое встраивание только при взаимодействии .
Например, мы можем использовать:
- lite-vimeo-embed для проигрывателя Vimeo,
- lite-vimeo для проигрывателя Vimeo,
- lite-youtube-embed для проигрывателя YouTube,
- react-live-chat-loader для живого чата (кейс и еще один кейс),
- ленивый фрейм для фреймов.
Одна из причин, по которой менеджеры тегов обычно имеют большой размер, заключается в том, что одновременно выполняется множество экспериментов, а также множество пользовательских сегментов, URL-адресов страниц, сайтов и т. д., поэтому, по словам Энди, их сокращение может уменьшить как размер загрузки и время, необходимое для выполнения скрипта в браузере.
А еще есть антимерцающие фрагменты. Сторонние компании, такие как Google Optimize, Visual Web Optimizer (VWO) и другие, единодушно используют их. Эти фрагменты обычно вводятся вместе с выполнением A/B-тестов : чтобы избежать мерцания между различными тестовыми сценариями, они скрывают
body
документа сopacity: 0
, а затем добавляют функцию, которая вызывается через несколько секунд, чтобы вернутьopacity
. . Это часто приводит к значительным задержкам рендеринга из-за огромных затрат на выполнение на стороне клиента.Поэтому следите за тем, как часто срабатывает тайм-аут антимерцания, и сокращайте тайм-аут. По умолчанию блокирует отображение вашей страницы на срок до 4 секунд, что снижает коэффициент конверсии. По словам Тима Кадлека, «друзья не позволяют друзьям проводить A/B-тестирование на стороне клиента». A/B-тестирование на стороне сервера в CDN (например, Edge Computing или Edge Slice Rerendering) всегда является более эффективным вариантом.
Если вам приходится иметь дело со всемогущим Диспетчером тегов Google , Барри Поллард предлагает несколько рекомендаций по сдерживанию влияния Диспетчера тегов Google. Кроме того, Кристиан Шефер исследует стратегии загрузки рекламы.
Будьте осторожны: некоторые сторонние виджеты скрывают себя от инструментов аудита, поэтому их может быть сложнее обнаружить и измерить. Чтобы провести стресс-тестирование третьих сторон, изучите сводные данные снизу вверх на странице профиля производительности в DevTools, проверьте, что произойдет, если запрос заблокирован или истекло время ожидания — для последнего вы можете использовать сервер
blackhole.webpagetest.org
Blackhole blackhole.webpagetest.org, который вы может указать определенные домены в вашем файлеhosts
.Какие у нас тогда есть варианты? Рассмотрите возможность использования сервис-воркеров, ускорив загрузку ресурса с тайм -аутом, и если ресурс не ответил в течение определенного тайм-аута, верните пустой ответ, чтобы указать браузеру продолжить анализ страницы. Вы также можете регистрировать или блокировать сторонние запросы, которые не были успешными или не соответствуют определенным критериям. Если вы можете, загрузите сторонний скрипт со своего собственного сервера, а не с сервера поставщика, и лениво загрузите их.
Другой вариант — установить политику безопасности содержимого (CSP) , чтобы ограничить влияние сторонних сценариев, например запретить загрузку аудио или видео. Лучший вариант — встроить скрипты через
<iframe>
, чтобы скрипты работали в контексте iframe и, следовательно, не имели доступа к DOM страницы и не могли запускать произвольный код в вашем домене. Интерактивные фреймы могут быть дополнительно ограничены с помощью атрибутаsandbox
, поэтому вы можете отключить любую функциональность, которую может выполнять фреймворк, например, запретить выполнение сценариев, запретить оповещения, отправку форм, плагины, доступ к верхней навигации и т. д.Вы также можете держать третьих лиц под контролем с помощью анализа производительности в браузере с помощью политик функций, относительно новой функции, которая позволяет вам
включение или отключение определенных функций браузера на вашем сайте. (Кроме того, его также можно использовать, чтобы избежать слишком больших и неоптимизированных изображений, неразмерных медиафайлов, сценариев синхронизации и прочего). В настоящее время поддерживается в браузерах на основе Blink. /* Via Tim Kadlec. https://timkadlec.com/remembers/2020-02-20-in-browser-performance-linting-with-feature-policies/ */ /* Block the use of the Geolocation API with a Feature-Policy header. */ Feature-Policy: geolocation 'none'
/* Via Tim Kadlec. https://timkadlec.com/remembers/2020-02-20-in-browser-performance-linting-with-feature-policies/ */ /* Block the use of the Geolocation API with a Feature-Policy header. */ Feature-Policy: geolocation 'none'
Поскольку многие сторонние скрипты работают в iframe, вам, вероятно, придется тщательно ограничивать их допуски. Песочница iframe — это всегда хорошая идея, и каждое из ограничений можно снять с помощью ряда
allow
значений атрибутаsandbox
. Песочница поддерживается почти везде, поэтому ограничивайте сторонние скрипты до минимума того, что им разрешено делать.Рассмотрите возможность использования Intersection Observer; это позволило бы размещать рекламу в iframe , при этом отправляя события или получая необходимую информацию из DOM (например, видимость рекламы). Следите за новыми политиками, такими как политика функций, ограничения на размер ресурсов и приоритет ЦП/пропускной способности, чтобы ограничить вредоносные веб-функции и сценарии, которые замедляют работу браузера, например синхронные сценарии, синхронные запросы XHR, document.write и устаревшие реализации.
Наконец, при выборе стороннего сервиса рассмотрите возможность проверки ThirdPartyWeb.Today Патрика Халса, сервиса, который группирует все сторонние скрипты по категориям (аналитика, социальные сети, реклама, хостинг, менеджер тегов и т. д.) и визуализирует, как долго скрипты объекта взять на выполнение (в среднем). Очевидно, что самые крупные объекты оказывают наихудшее влияние на производительность страниц, на которых они находятся. Просто пробежав страницу, вы получите представление о ожидаемой производительности.
Ах, и не забывайте об обычных подозреваемых: вместо сторонних виджетов для обмена мы можем использовать статические кнопки обмена в социальных сетях (например, SSBG) и статические ссылки на интерактивные карты вместо интерактивных карт.
- Правильно установите заголовки кэша HTTP.
Кэширование кажется такой очевидной вещью, но это может быть довольно сложно сделать правильно. Нам нужно перепроверить, чтоexpires
,max-age
,cache-control
и другие заголовки кэша HTTP были установлены правильно. Без надлежащих заголовков кеша HTTP браузеры автоматически установят их на 10% от времени, прошедшего с моментаlast-modified
, что приведет к потенциальному недостаточному или избыточному кэшированию.В общем, ресурсы должны кэшироваться либо на очень короткое время (если они могут измениться), либо на неопределенное время (если они статичны) — вы можете просто изменить их версию в URL-адресе, когда это необходимо. Вы можете назвать это стратегией Cache-Forever, в которой мы могли бы передавать заголовки
Cache-Control
иExpires
в браузер, чтобы срок действия активов истекал только через год. Следовательно, браузер даже не будет запрашивать актив, если он есть в кеше.Исключение составляют ответы API (например,
/api/user
). Чтобы предотвратить кеширование, мы можем использоватьprivate, no store
, а неmax-age=0, no-store
:Cache-Control: private, no-store
Используйте
Cache-control: immutable
, чтобы избежать повторной проверки длинных явных сроков жизни кеша, когда пользователи нажимают кнопку перезагрузки. В случае перезагрузкиimmutable
сохраняет HTTP-запросы и сокращает время загрузки динамического HTML, поскольку они больше не конкурируют с множеством ответов 304.Типичным примером, где мы хотим использовать
immutable
, являются активы CSS/JavaScript с хешем в имени. Для них мы, вероятно, хотим кэшировать как можно дольше и гарантировать, что они никогда не будут повторно проверены:Cache-Control: max-age: 31556952, immutable
Согласно исследованию Колина Бенделла,
immutable
сокращает количество переадресаций 304 примерно на 50%, поскольку даже при использованииmax-age
клиенты все равно повторно проверяют и блокируют при обновлении. Он поддерживается в Firefox, Edge и Safari, и Chrome все еще обсуждает этот вопрос.Согласно Web Almanac, «его использование выросло до 3,5%, и оно широко используется в сторонних ответах Facebook и Google».
Вы помните старую добрую устаревшую версию? Когда мы указываем время кэширования в заголовке ответа
Cache-Control
(напримерCache-Control: max-age=604800
), после истечения срока действияmax-age
браузер повторно извлекает запрошенный контент, что приводит к замедлению загрузки страницы. Этого замедления можно избежать с помощьюstale-while-revalidate
; по сути, он определяет дополнительное окно времени, в течение которого кеш может использовать устаревший ресурс, пока он проверяет его асинхронно в фоновом режиме. Таким образом он «скрывает» латентность (как в сети, так и на сервере) от клиентов.В июне-июле 2019 года Chrome и Firefox запустили поддержку
stale-while-revalidate
в заголовке HTTP Cache-Control, поэтому в результате это должно уменьшить последующие задержки загрузки страницы, поскольку устаревшие ресурсы больше не находятся на критическом пути. Результат: нулевой RTT для повторных просмотров.С осторожностью относитесь к заголовку вариации, особенно в отношении сетей CDN, и следите за вариантами представления HTTP, которые помогают избежать дополнительного кругового пути для проверки всякий раз, когда новый запрос немного (но не значительно) отличается от предыдущих запросов ( спасибо, Гай и Марк ! ).
Кроме того, дважды проверьте, что вы не отправляете ненужные заголовки (например
x-powered-by
,pragma
,x-ua-compatible
,expires
,X-XSS-Protection
и другие) и что вы включаете полезные заголовки безопасности и производительности (такие как какContent-Security-Policy
,X-Content-Type-Options
и другие). Наконец, не забывайте о снижении производительности запросов CORS в одностраничных приложениях.Примечание . Мы часто предполагаем, что кешированные ресурсы извлекаются мгновенно, но исследования показывают, что извлечение объекта из кеша может занять сотни миллисекунд. На самом деле, по словам Саймона Херна, «иногда сеть может быть быстрее, чем кеш, а извлечение ресурсов из кеша может быть дорогостоящим из-за большого количества кэшированных ресурсов (не размера файла) и устройств пользователя. Например: среднее извлечение из кеша Chrome OS удваивается с ~ 50 мс с 5 кэшированными ресурсами до ~ 100 мс с 25 ресурсами».
Кроме того, мы часто предполагаем, что размер пакета не является большой проблемой, и пользователи скачают его один раз, а затем будут использовать кешированную версию. В то же время, с CI/CD мы запускаем код в производство несколько раз в день, кеш каждый раз становится недействительным, поэтому кеширование имеет стратегическое значение.
Что касается кэширования, есть много ресурсов, которые стоит прочитать:
- Cache-Control for Civilians, подробное изучение всего кэширования с Гарри Робертсом.
- Учебник Heroku по заголовкам кэширования HTTP,
- Рекомендации по кэшированию, Джейк Арчибальд,
- Учебник по HTTP-кешированию Ильи Григорика,
- Сохраняйте актуальность с помощью функции «устаревшие при повторной проверке» от Джеффа Посника.
- CS Visualized: CORS Лидии Холли — отличное объяснение CORS, того, как он работает и как его понять.
- Говоря о CORS, вот небольшой обзор Политики одинакового происхождения от Эрика Портиса.
Оптимизация доставки
- Используем ли мы
defer
для асинхронной загрузки критического JavaScript?
Когда пользователь запрашивает страницу, браузер извлекает HTML и создает DOM, затем извлекает CSS и создает CSSOM, а затем создает дерево рендеринга, сопоставляя DOM и CSSOM. Если необходимо разрешить какой-либо JavaScript, браузер не начнет отображать страницу до тех пор, пока он не будет разрешен, что приведет к задержке отображения. Как разработчики, мы должны явно указать браузеру не ждать и начать рендеринг страницы. Для скриптов это можно сделать с помощью атрибутовdefer
иasync
в HTML.На практике оказывается, что лучше использовать
defer
вместоasync
. Ах, какая опять разница ? По словам Стива Содерса, как только приходятasync
скрипты, они сразу же выполняются — как только скрипт готов. Если это происходит очень быстро, например, когда скрипт уже находится в кеше, он может фактически заблокировать анализатор HTML. Сdefer
браузер не выполняет скрипты до тех пор, пока не будет проанализирован HTML. Итак, если вам не нужно, чтобы JavaScript выполнялся перед началом рендеринга, лучше использоватьdefer
. Кроме того, несколько асинхронных файлов будут выполняться в недетерминированном порядке.Стоит отметить, что существует несколько неправильных представлений об
async
иdefer
. Самое главное,async
не означает, что код будет выполняться всякий раз, когда сценарий готов; это означает, что он будет запускаться всякий раз, когда сценарии будут готовы и будет выполнена вся предыдущая работа по синхронизации. По словам Гарри Робертса, «если вы поместитеasync
сценарий после сценариев синхронизации, вашasync
сценарий будет настолько же быстрым, как и ваш самый медленный сценарий синхронизации».Кроме того, не рекомендуется использовать одновременно
async
иdefer
. Современные браузеры поддерживают оба атрибута, но всякий раз, когда используются оба атрибута,async
всегда будет побеждать.Если вы хотите углубиться в детали, Милица Михайлия написала очень подробное руководство по ускоренному построению DOM, в котором подробно рассматриваются спекулятивный анализ, асинхронность и отложенное выполнение.
- Ленивая загрузка дорогих компонентов с IntersectionObserver и подсказками приоритета.
В общем, рекомендуется лениво загружать все дорогостоящие компоненты, такие как тяжелый JavaScript, видео, фреймы, виджеты и, возможно, изображения. Нативная отложенная загрузка уже доступна для изображений и фреймов с атрибутомloading
(только Chromium). Под капотом этот атрибут откладывает загрузку ресурса до тех пор, пока он не достигнет расчетного расстояния от области просмотра.<!-- Lazy loading for images, iframes, scripts. Probably for images outside of the viewport. --> <img loading="lazy" ... /> <iframe loading="lazy" ... /> <!-- Prompt an early download of an asset. For critical images, eg hero images. --> <img loading="eager" ... /> <iframe loading="eager" ... />
Этот порог зависит от нескольких вещей, от типа загружаемого ресурса изображения до эффективного типа соединения. Но эксперименты, проведенные с использованием Chrome на Android, показывают, что в 4G 97,5% изображений ниже сгиба, загружаемых отложенно, были полностью загружены в течение 10 мс после того, как стали видимыми, поэтому это должно быть безопасно.
Мы также можем использовать атрибут
importance
(high
илиlow
) для элемента<script>
,<img>
или<link>
(только для Blink). На самом деле, это отличный способ снизить приоритет изображений в каруселях, а также изменить приоритет сценариев. Однако иногда нам может понадобиться немного более детальный контроль.<!-- When the browser assigns "High" priority to an image, but we don't actually want that. --> <img src="less-important-image.svg" importance="low" ... /> <!-- We want to initiate an early fetch for a resource, but also deprioritize it. --> <link rel="preload" importance="low" href="/script.js" as="script" />
Самый эффективный способ сделать несколько более сложную ленивую загрузку — использовать Intersection Observer API, который позволяет асинхронно отслеживать изменения в пересечении целевого элемента с элементом-предком или с окном просмотра документа верхнего уровня. По сути, вам нужно создать новый объект
IntersectionObserver
, который получает функцию обратного вызова и набор параметров. Затем мы добавляем цель для наблюдения.Функция обратного вызова выполняется, когда цель становится видимой или невидимой, поэтому, когда она перехватывает область просмотра, вы можете начать выполнять некоторые действия до того, как элемент станет видимым. На самом деле, у нас есть детальный контроль над тем, когда должен вызываться обратный вызов наблюдателя, с
rootMargin
(поле вокруг корня) иthreshold
(одно число или массив чисел, которые указывают, на какой процент видимости цели мы нацелены).Алехандро Гарсия Англада опубликовал удобный учебник о том, как это реализовать на самом деле, Рахул Нанвани написал подробный пост о ленивой загрузке изображений переднего плана и фона, а Google Fundamentals также предоставил подробный учебник по ленивой загрузке изображений и видео с помощью Intersection Observer.
Помните художественные лонгриды с движущимися и липкими объектами? С помощью Intersection Observer также можно реализовать эффективное прокручивание.
Проверьте еще раз, что еще вы могли бы лениво загрузить. Даже ленивая загрузка строк перевода и эмодзи может помочь. Таким образом, Mobile Twitter удалось добиться ускорения выполнения JavaScript на 80 % благодаря новому конвейеру интернационализации.
Небольшое предостережение: стоит отметить, что отложенная загрузка должна быть скорее исключением, чем правилом. Вероятно, нецелесообразно лениво загружать все, что вы действительно хотите, чтобы люди увидели быстро, например, изображения страниц продукта, основные изображения или скрипт, необходимый для того, чтобы основная навигация стала интерактивной.
- Загружайте изображения постепенно.
Вы даже можете поднять ленивую загрузку на новый уровень, добавив прогрессивную загрузку изображений на свои страницы. Как и в Facebook, Pinterest, Medium и Wolt, вы можете сначала загрузить низкокачественные или даже размытые изображения, а затем, когда страница продолжает загружаться, заменить их полноценными версиями с помощью технологии BlurHash или LQIP (заполнители изображений низкого качества). техника.Мнения расходятся, улучшают ли эти методы взаимодействие с пользователем или нет, но они определенно сокращают время до первой отрисовки контента. Мы даже можем автоматизировать его, используя SQIP, который создает низкокачественную версию изображения в качестве заполнителя SVG, или заполнители Gradient Image Placeholders с линейными градиентами CSS.
Эти заполнители могут быть встроены в HTML, поскольку они естественным образом хорошо сжимаются методами сжатия текста. В своей статье Дин Хьюм описал, как эту технику можно реализовать с помощью Intersection Observer.
Отступать? Если браузер не поддерживает наблюдатель пересечений, мы все равно можем отложенно загрузить полифилл или сразу загрузить изображения. И для этого есть даже библиотека.
Хотите пофантазировать? Вы можете отслеживать свои изображения и использовать примитивные формы и края для создания легкого заполнителя SVG, сначала загрузить его, а затем перейти от векторного изображения заполнителя к (загруженному) растровому изображению.
- Вы откладываете рендеринг с помощью
content-visibility
?
Для сложного макета с большим количеством блоков контента, изображений и видео декодирование данных и рендеринг пикселей может быть довольно дорогостоящей операцией, особенно на недорогих устройствах. С помощьюcontent-visibility: auto
мы можем предложить браузеру пропустить макет дочерних элементов, пока контейнер находится за пределами области просмотра.Например, вы можете пропустить рендеринг нижнего колонтитула и поздних разделов при начальной загрузке:
footer { content-visibility: auto; contain-intrinsic-size: 1000px; /* 1000px is an estimated height for sections that are not rendered yet. */ }
Обратите внимание, что content-visibility: auto; ведет себя как переполнение: скрыто; , но вы можете исправить это, применив
padding-left
иpadding-right
вместо значения по умолчаниюmargin-left: auto;
,margin-right: auto;
и заявленная ширина. Заполнение в основном позволяет элементам переполнять блок содержимого и входить в блок заполнения, не выходя из модели блока в целом и не обрезаясь.Кроме того, имейте в виду, что вы можете ввести некоторые CLS, когда новый контент в конечном итоге будет отображаться, поэтому рекомендуется использовать
contain-intrinsic-size
с заполнителем правильного размера ( спасибо, Уна! ).У Thijs Terluin есть гораздо больше подробностей об обоих свойствах и о том, как браузер вычисляет вложенный
contain-intrinsic-size
содержимого, Malte Ubl показывает, как вы можете его вычислить, а краткое пояснение Джейка и Сурма объясняет, как все это работает.И если вам нужно получить немного больше детализации, с помощью CSS Containment вы можете вручную пропустить макет, стиль и работу по рисованию для потомков узла DOM, если вам нужен только размер, выравнивание или вычисленные стили для других элементов — или элемент в настоящее время вне холста.
- Вы откладываете декодирование с помощью
decoding="async"
?
Иногда контент появляется за кадром, но мы хотим быть уверены, что он доступен, когда он нужен клиентам — в идеале, ничего не блокируя на критическом пути, а декодируя и отображая асинхронно. Мы можем использоватьdecoding="async"
, чтобы дать браузеру разрешение на декодирование изображения вне основного потока, избегая воздействия на пользователя процессорного времени, используемого для декодирования изображения (через Malte Ubl):<img decoding="async" … />
В качестве альтернативы, для закадровых изображений мы можем сначала отобразить заполнитель, а когда изображение находится в области просмотра, используя IntersectionObserver, инициировать сетевой вызов для загрузки изображения в фоновом режиме. Кроме того, мы можем отложить рендеринг до декодирования с помощью img.decode() или загрузить изображение, если API декодирования изображений недоступен.
Например, при рендеринге изображения мы можем использовать плавную анимацию. Кэти Хемпениус и Эдди Османи поделились своими мыслями в своем выступлении «Скорость в масштабе: советы и хитрости веб-производительности из окопов».
- Вы создаете и обслуживаете критический CSS?
Чтобы гарантировать, что браузеры начнут отображать вашу страницу как можно быстрее, стало обычной практикой собирать весь CSS, необходимый для начала отображения первой видимой части страницы (известный как «критический CSS» или «CSS верхней части страницы»). ") и включить его в<head>
страницы, тем самым уменьшив круговые обращения. Из-за ограниченного размера пакетов, которыми обмениваются на этапе медленного старта, ваш бюджет на критический CSS составляет около 14 КБ.Если вы пойдете дальше этого, браузеру потребуются дополнительные обращения, чтобы получить больше стилей. CriticalCSS и Critical позволяют выводить критический CSS для каждого используемого вами шаблона. Однако, по нашему опыту, никакая автоматическая система не была лучше, чем ручной сбор критически важных CSS для каждого шаблона, и действительно, это подход, к которому мы недавно вернулись.
Затем вы можете встроить критический CSS и лениво загрузить остальные с помощью плагина critters Webpack. Если возможно, рассмотрите возможность использования подхода условного встраивания, используемого Filament Group, или преобразуйте встроенный код в статические ресурсы на лету.
Если вы в настоящее время загружаете свой полный CSS асинхронно с такими библиотеками, как loadCSS, в этом нет необходимости. С помощью
media="print"
вы можете заставить браузер асинхронно извлекать CSS, но применять его к среде экрана после его загрузки. ( спасибо, Скотт! )<!-- Via Scott Jehl. https://www.filamentgroup.com/lab/load-css-simpler/ --> <!-- Load CSS asynchronously, with low priority --> <link rel="stylesheet" href="full.css" media="print" onload="this.media='all'" />
При сборе всех важных CSS-файлов для каждого шаблона обычно исследуют только верхнюю часть страницы. Тем не менее, для сложных макетов может быть хорошей идеей включить основу макета, чтобы избежать огромных затрат на пересчет и перерисовку, что в результате повредит вашей оценке Core Web Vitals.
Что делать, если пользователь получает URL-адрес, ведущий прямо в середину страницы, но CSS еще не загружен? В этом случае стало обычным скрывать некритическое содержимое, например, с помощью
opacity: 0;
во встроенном CSS иopacity: 1
в полном файле CSS и отображать его, когда CSS доступен. Однако у него есть серьезный недостаток , поскольку пользователи с медленным соединением могут никогда не прочитать содержимое страницы. Вот почему лучше всегда держать содержимое видимым, даже если оно может быть оформлено неправильно.Помещение критического CSS (и других важных ресурсов) в отдельный файл в корневом домене имеет преимущества, иногда даже больше, чем встраивание, благодаря кэшированию. Chrome спекулятивно открывает второе HTTP-соединение с корневым доменом при запросе страницы, что устраняет необходимость в TCP-соединении для получения этого CSS. Это означает, что вы можете создать набор важных -CSS-файлов (например, crypto -homepage.css , crypto-product-page.css и т. д.) и обслуживать их из своего корня без необходимости встраивания. ( спасибо, Филипп! )
Небольшое предостережение: при использовании HTTP/2 важные CSS-коды можно хранить в отдельном CSS-файле и доставлять через сервер, не раздувая HTML-код. Загвоздка в том, что отправка на сервер была проблематичной из-за множества подводных камней и условий гонки в разных браузерах. Он никогда не поддерживался последовательно и имел некоторые проблемы с кэшированием (см. слайд 114 презентации Hooman Beheshti и далее).
На самом деле эффект может быть отрицательным и привести к раздуванию сетевых буферов, препятствуя доставке подлинных кадров в документе. Поэтому неудивительно, что на данный момент Chrome планирует отказаться от поддержки Server Push.
- Поэкспериментируйте с перегруппировкой правил CSS.
Мы привыкли к критическому CSS, но есть несколько оптимизаций, которые могли бы выйти за рамки этого. Гарри Робертс провел замечательное исследование с довольно неожиданными результатами. Например, было бы неплохо разделить основной файл CSS на отдельные медиа-запросы. Таким образом, браузер будет извлекать критический CSS с высоким приоритетом, а все остальное с низким приоритетом — полностью вне критического пути.Кроме того, избегайте размещения
<link rel="stylesheet" />
передasync
фрагментами. Если скрипты не зависят от таблиц стилей, рассмотрите возможность размещения блокирующих скриптов над блокирующими стилями. Если они это сделают, разделите этот JavaScript на две части и загрузите его по обе стороны от вашего CSS.Скотт Джел решил еще одну интересную проблему, кэшировав встроенный файл CSS с помощью сервис-воркера, — обычная проблема, знакомая тем, кто использует критически важный CSS. По сути, мы добавляем атрибут ID к элементу
style
, чтобы его было легко найти с помощью JavaScript, затем небольшой фрагмент JavaScript находит этот CSS и использует Cache API для его сохранения в локальном кеше браузера (с типом содержимогоtext/css
) для использования на последующих страницах. Чтобы избежать встраивания на последующих страницах и вместо этого ссылаться на кэшированные ресурсы извне, мы затем устанавливаем файл cookie при первом посещении сайта. Вуаля!Стоит отметить, что динамические стили тоже могут быть дорогими, но обычно только в тех случаях, когда вы полагаетесь на сотни одновременно отображаемых составных компонентов. Поэтому, если вы используете CSS-in-JS, убедитесь, что ваша библиотека CSS-in-JS оптимизирует выполнение, когда ваш CSS не зависит от темы или свойств, и не перекомпоновывайте стилизованные компоненты . Аггелос Арванитакис делится подробностями о затратах производительности на CSS-in-JS.
- Вы транслируете ответы?
Часто забываемые и игнорируемые потоки предоставляют интерфейс для чтения или записи асинхронных фрагментов данных, только часть которых может быть доступна в памяти в любой момент времени. По сути, они позволяют странице, отправившей первоначальный запрос, начать работу с ответом, как только станет доступен первый фрагмент данных, и используют синтаксические анализаторы, оптимизированные для потоковой передачи, для постепенного отображения контента.Мы могли бы создать один поток из нескольких источников. Например, вместо того, чтобы обслуживать пустую оболочку пользовательского интерфейса и позволять JavaScript заполнять ее, вы можете позволить сервис-воркеру создать поток, в котором оболочка поступает из кеша, а тело — из сети. Как заметил Джефф Посник, если ваше веб-приложение работает на базе CMS, которая отображает HTML-код на сервере путем сшивания частичных шаблонов, эта модель напрямую преобразуется в использование потоковых ответов, а логика шаблонов копируется в сервис-воркере, а не на вашем сервере. В статье Джейка Арчибальда «Год веб-потоков» рассказывается, как именно вы можете их построить. Прирост производительности весьма заметен.
Одним из важных преимуществ потоковой передачи всего HTML-ответа является то, что HTML-код, отображаемый во время начального запроса навигации, может в полной мере использовать преимущества потокового синтаксического анализатора HTML браузера. Фрагменты HTML, которые вставляются в документ после загрузки страницы (как это часто бывает с контентом, заполняемым с помощью JavaScript), не могут использовать преимущества этой оптимизации.
Поддержка браузера? По-прежнему достигается частичная поддержка в Chrome, Firefox, Safari и Edge с поддержкой API и Service Workers, которые поддерживаются во всех современных браузерах. И если вы снова чувствуете себя предприимчивым, вы можете проверить экспериментальную реализацию потоковых запросов, которая позволяет вам начать отправку запроса, продолжая генерировать тело. Доступно в Chrome 85.
- Подумайте о том, чтобы ваши компоненты знали о подключении.
Данные могут быть дорогими, и с ростом полезной нагрузки мы должны уважать пользователей, которые выбирают экономию данных при доступе к нашим сайтам или приложениям. Заголовок запроса подсказки клиента Save-Data позволяет нам настроить приложение и полезную нагрузку для пользователей с ограниченными затратами и производительностью.Фактически, вы можете переписать запросы для изображений с высоким DPI на изображения с низким DPI, удалить веб-шрифты, причудливые эффекты параллакса, миниатюры предварительного просмотра и бесконечную прокрутку, отключить автовоспроизведение видео, отправку сервером, уменьшить количество отображаемых элементов и понизить качество изображения или даже изменить способ доставки разметки. Тим Верике опубликовал очень подробную статью о стратегиях экономии данных, в которой представлено множество вариантов сохранения данных.
Кто использует
save-data
, вам может быть интересно? У 18 % пользователей Android Chrome по всему миру включен упрощенный режим (с включенным параметром «Save-Data
»), и, скорее всего, это число будет выше. Согласно исследованию Саймона Херна, самый высокий уровень подписки на более дешевых устройствах, но есть много исключений. Например: у пользователей в Канаде уровень отказа составляет более 34% (по сравнению с ~ 7% в США), а у пользователей последнего флагмана Samsung этот показатель составляет почти 18% во всем мире.При включенном режиме
Save-Data
Chrome Mobile обеспечивает оптимизированную работу, т. е. работу в Интернете через прокси с отложенными сценариями , принудительноеfont-display: swap
и принудительная отложенная загрузка. Просто более разумно создавать опыт самостоятельно, а не полагаться на браузер для выполнения этих оптимизаций.Заголовок в настоящее время поддерживается только в Chromium, в версии Chrome для Android или через расширение Data Saver на настольном устройстве. Наконец, вы также можете использовать API сетевой информации для доставки дорогостоящих модулей JavaScript, изображений и видео с высоким разрешением в зависимости от типа сети. Network Information API и, в частности,
navigator.connection.effectiveType
. EffectiveType используют значенияRTT
,downlink
,effectiveType
(и некоторые другие), чтобы обеспечить представление соединения и данных, которые могут обрабатывать пользователи.В этом контексте Макс Бок говорит о компонентах, поддерживающих подключение, а Эдди Османи говорит об адаптивном обслуживании модулей. Например, с помощью React мы могли бы написать компонент, который будет отображаться по-разному для разных типов подключения. Как предположил Макс, компонент
<Media />
в новостной статье может выводить:-
Offline
: заполнитель сalt
текстом, -
2G
/режимsave-data
: изображение с низким разрешением, -
3G
на экране без Retina: изображение среднего разрешения, -
3G
на экранах Retina: изображение Retina в высоком разрешении, -
4G
: HD-видео.
Дин Хьюм предлагает практическую реализацию аналогичной логики с помощью сервисного работника. Для видео мы могли бы отображать видеопостер по умолчанию, а затем отображать значок «Воспроизвести», а также оболочку видеоплеера, метаданные видео и т. д. при лучшем соединении. В качестве запасного варианта для неподдерживающих браузеров мы могли бы прослушивать событие
canplaythrough
и использоватьPromise.race()
для тайм-аута загрузки источника, если событиеcanplaythrough
не срабатывает в течение 2 секунд.Если вы хотите погрузиться немного глубже, вот несколько ресурсов для начала:
- Эдди Османи показывает, как реализовать адаптивное обслуживание в React.
- React Adaptive Loading Hooks & Utilities предоставляет фрагменты кода для React,
- Нетанель Базель исследует компоненты с поддержкой подключения в Angular,
- Теодор Ворилас рассказывает, как работает обслуживание адаптивных компонентов с помощью API сетевой информации в Vue.
- Умар Ханса показывает, как выборочно загружать/выполнять дорогостоящий JavaScript.
-
- Рассмотрите возможность того, чтобы ваши компоненты учитывали память устройства.
Однако сетевое подключение дает нам только одну перспективу в контексте пользователя. Идя дальше, вы также можете динамически настраивать ресурсы в зависимости от доступной памяти устройства с помощью API памяти устройства.navigator.deviceMemory
возвращает объем оперативной памяти устройства в гигабайтах, округленный до ближайшей степени двойки. В API также есть заголовок Client Hints,Device-Memory
, который сообщает то же значение.Бонус : Умар Ханса показывает, как отложить дорогостоящие сценарии с помощью динамического импорта, чтобы изменить работу в зависимости от памяти устройства, сетевого подключения и аппаратного параллелизма.
- Разогрейте соединение, чтобы ускорить доставку.
Используйте подсказки ресурсов, чтобы сэкономить время наdns-prefetch
(который выполняет поиск DNS в фоновом режиме),preconnect
(который просит браузер начать подтверждение соединения (DNS, TCP, TLS) в фоновом режиме),prefetch
(который запрашивает браузер для запроса ресурса) иpreload
(которая, среди прочего, выполняет предварительную выборку ресурсов без их выполнения). Хорошо поддерживается в современных браузерах, поддержка скоро появится в Firefox.Помните
prerender
? Подсказка ресурса, используемая для того, чтобы предложить браузеру построить всю страницу в фоновом режиме для следующей навигации. Проблемы с реализацией были довольно проблематичными, начиная от огромного объема памяти и использования полосы пропускания и заканчивая многочисленными зарегистрированными аналитическими обращениями и показами рекламы.Неудивительно, что он устарел, но команда Chrome вернула его как механизм NoState Prefetch. На самом деле, Chrome вместо этого обрабатывает подсказку
prerender
обработки как предварительную выборку NoState, поэтому мы все еще можем использовать ее сегодня. Как объясняет Кэти Хемпениус в этой статье, «как и предварительная отрисовка, NoState Prefetch извлекает ресурсы заранее , но, в отличие от предварительной отрисовки, она не выполняет JavaScript и не отображает какую-либо часть страницы заранее».Предварительная выборка NoState использует только ~45 МБ памяти, а извлекаемые подресурсы будут выбираться с приоритетом сети
IDLE
. Начиная с Chrome 69, NoState Prefetch добавляет заголовок Purpose: Prefetch ко всем запросам, чтобы их можно было отличить от обычного просмотра.Кроме того, следите за альтернативами предварительного рендеринга и порталами, новой попыткой предварительного рендеринга с учетом конфиденциальности, который обеспечит
preview
содержимого для плавной навигации.Использование подсказок ресурсов, вероятно , самый простой способ повысить производительность , и он действительно хорошо работает. Когда что использовать? Как объяснила Эдди Османи, разумно предварительно загружать ресурсы, которые, как мы знаем, с большой вероятностью будут использоваться на текущей странице и для будущих переходов через несколько границ навигации, например, пакеты Webpack, необходимые для страниц, которые пользователь еще не посещал.
В статье Эдди «Приоритеты загрузки в Chrome» показано, как именно Chrome интерпретирует подсказки ресурсов, поэтому, как только вы решили, какие ресурсы имеют решающее значение для рендеринга, вы можете назначить им высокий приоритет. Чтобы увидеть, как ваши запросы расставлены по приоритетам, вы можете включить столбец «приоритет» в таблице сетевых запросов Chrome DevTools (а также Safari).
Большую часть времени в эти дни мы будем использовать по крайней мере
preconnect
иdns-prefetch
, и мы будем осторожны с использованиемprefetch
,preload
иprerender
. Обратите внимание, что даже сpreconnect
иdns-prefetch
у браузера есть ограничение на количество хостов, к которым он будет искать/подключаться параллельно, поэтому можно с уверенностью упорядочить их на основе приоритета ( спасибо Филиппу Теллису! ).Поскольку шрифты обычно являются важными активами на странице, иногда рекомендуется запросить у браузера загрузку важных шрифтов с
preload
загрузкой. Тем не менее, дважды проверьте, действительно ли это помогает производительности, поскольку при предварительной загрузке шрифтов существует загадка приоритетов: посколькуpreload
считается очень важной, она может обойти даже более важные ресурсы, такие как критический CSS. ( спасибо, Барри! )<!-- Loading two rendering-critical fonts, but not all their weights. --> <!-- crossorigin="anonymous" is required due to CORS. Without it, preloaded fonts will be ignored. https://github.com/w3c/preload/issues/32 via https://twitter.com/iamakulov/status/1275790151642423303 --> <link rel="preload" as="font" href="Elena-Regular.woff2" type="font/woff2" crossorigin="anonymous" media="only screen and (min-width: 48rem)" /> <link rel="preload" as="font" href="Mija-Bold.woff2" type="font/woff2" crossorigin="anonymous" media="only screen and (min-width: 48rem)" />
<!-- Loading two rendering-critical fonts, but not all their weights. --> <!-- crossorigin="anonymous" is required due to CORS. Without it, preloaded fonts will be ignored. https://github.com/w3c/preload/issues/32 via https://twitter.com/iamakulov/status/1275790151642423303 --> <link rel="preload" as="font" href="Elena-Regular.woff2" type="font/woff2" crossorigin="anonymous" media="only screen and (min-width: 48rem)" /> <link rel="preload" as="font" href="Mija-Bold.woff2" type="font/woff2" crossorigin="anonymous" media="only screen and (min-width: 48rem)" />
Поскольку
<link rel="preload">
принимает атрибутmedia
, вы можете выбрать выборочную загрузку ресурсов на основе правил запроса@media
, как показано выше.Кроме того, мы можем использовать
imagesrcset
иimagesizes
для более быстрой предварительной загрузки недавно обнаруженных главных изображений или любых изображений, загружаемых через JavaScript, например постеры фильмов:<!-- Addy Osmani. https://addyosmani.com/blog/preload-hero-images/ --> <link rel="preload" as="image" href="poster.jpg" image image>
<!-- Addy Osmani. https://addyosmani.com/blog/preload-hero-images/ --> <link rel="preload" as="image" href="poster.jpg" image image>
Мы также можем предварительно загрузить JSON как fetch , чтобы он был обнаружен до того, как JavaScript запросит его:
<!-- Addy Osmani. https://addyosmani.com/blog/preload-hero-images/ --> <link rel="preload" as="fetch" href="foo.com/api/movies.json" crossorigin>
Мы также можем динамически загружать JavaScript, что эффективно для ленивого выполнения скрипта.
/* Adding a preload hint to the head */ var preload = document.createElement("link"); link.href = "myscript.js"; link.rel = "preload"; link.as = "script"; document.head.appendChild(link); /* Injecting a script when we want it to execute */ var script = document.createElement("script"); script.src = "myscript.js"; document.body.appendChild(script);
Следует иметь в виду несколько нюансов:
preload
загрузка хороша для перемещения времени начала загрузки ресурса ближе к исходному запросу, но предварительно загруженные ресурсы попадают в кеш памяти , привязанный к странице, делающей запрос.preload
хорошо сочетается с кешем HTTP: сетевой запрос никогда не отправляется, если элемент уже находится в кеше HTTP.Следовательно, это полезно для недавно обнаруженных ресурсов, основных изображений, загружаемых через
background-image
, встраивания критически важного CSS (или JavaScript) и предварительной загрузки остальной части CSS (или JavaScript).Тег
preload
может инициировать предварительную загрузку только после того, как браузер получит HTML-код с сервера и упреждающий синтаксический анализатор найдет тегpreload
. Предварительная загрузка через заголовок HTTP может быть немного быстрее, поскольку нам не нужно ждать, пока браузер проанализирует HTML, чтобы начать запрос (хотя это обсуждается).Ранние подсказки помогут еще больше, позволяя выполнять предварительную загрузку еще до того, как будут отправлены заголовки ответов для HTML (на дорожной карте в Chromium, Firefox). Кроме того, подсказки по приоритетам помогут нам указать приоритеты загрузки для скриптов.
Остерегайтесь : если вы используете
preload
,as
должно быть определено, иначе ничего не загружается, а также предварительно загруженные шрифты без атрибутаcrossorigin
будут выполнять двойную выборку. Если вы используетеprefetch
, остерегайтесь проблем с заголовкомAge
в Firefox.
- Используйте сервис-воркеры для кэширования и отката сети.
Никакая оптимизация производительности по сети не может быть быстрее, чем локально сохраненный кеш на компьютере пользователя (хотя есть и исключения). Если ваш веб-сайт работает по протоколу HTTPS, мы можем кэшировать статические ресурсы в кеше сервис-воркера и хранить автономные запасные варианты (или даже автономные страницы) и извлекать их с компьютера пользователя, а не обращаться в сеть.Как предложил Фил Уолтон, с помощью сервис-воркеров мы можем отправлять меньшие полезные данные HTML, программно генерируя наши ответы. Сервисный работник может запросить с сервера лишь минимальный объем необходимых ему данных (например, частичный HTML-контент, файл Markdown, данные JSON и т. д.), а затем программно преобразовать эти данные в полный HTML-документ. Таким образом, как только пользователь посещает сайт и сервис-воркер установлен, пользователь больше никогда не будет запрашивать полную HTML-страницу. Влияние на производительность может быть весьма впечатляющим.
Поддержка браузера? Сервисные работники широко поддерживаются, и в любом случае запасным вариантом является сеть. Помогает ли это повысить производительность ? О да, это так. И это становится лучше, например, с фоновой загрузкой, позволяющей фоновую загрузку/выгрузку также через работника службы.
Существует несколько вариантов использования сервис-воркера. Например, вы можете реализовать функцию «Сохранить для автономного режима», обрабатывать поврежденные изображения, ввести обмен сообщениями между вкладками или предоставить различные стратегии кэширования в зависимости от типов запросов. В общем, распространенная надежная стратегия заключается в том, чтобы хранить оболочку приложения в кэше сервис-воркера вместе с несколькими важными страницами, такими как автономная страница, главная страница и все остальное, что может быть важно в вашем случае.
Однако есть несколько ошибок, о которых следует помнить. С сервис-воркером нам нужно остерегаться запросов диапазона в Safari (если вы используете Workbox для сервис-воркера, у него есть модуль запроса диапазона). Если вы когда-нибудь сталкивались с
DOMException: Quota exceeded.
ошибка в консоли браузера, затем загляните в статью Джерардо Когда 7 КБ равно 7 МБ.Как пишет Джерардо: «Если вы создаете прогрессивное веб-приложение и сталкиваетесь с раздутым хранилищем кеша, когда ваш сервисный работник кэширует статические ресурсы, обслуживаемые из CDN, убедитесь, что для ресурсов из разных источников существует правильный заголовок ответа CORS, вы не кэшируете непрозрачные ответы. с вашим сервис-воркером вы непреднамеренно включаете ресурсы изображения из разных источников в режим CORS, добавляя атрибут
crossorigin
к тегу<img>
».Существует множество отличных ресурсов для начала работы с сервис-воркерами:
- Мышление сервисного работника, которое поможет вам понять, как сервисные работники работают за кулисами, и что нужно понимать при их создании.
- Крис Фердинанди (Chris Ferdinandi) опубликовал большую серию статей о сервис-воркерах, в которых объясняется, как создавать автономные приложения, и рассматриваются различные сценарии, от сохранения недавно просмотренных страниц в автономном режиме до установки даты истечения срока действия для элементов в кэше сервис-воркеров.
- Подводные камни сервис-воркеров и передовой опыт, а также несколько советов о сфере применения, отсрочке регистрации сервис-воркера и кэшировании сервис-воркера.
- Отличная серия статей Айра Адеринокуна «Сначала в автономном режиме» с Service Worker и стратегией предварительного кэширования оболочки приложения.
- Service Worker: Введение с практическими советами о том, как использовать Service Worker для многофункционального автономного взаимодействия, периодической фоновой синхронизации и push-уведомлений.
- Всегда стоит обратиться к старой доброй оффлайн-поваренной книге Джейка Арчибальда с рядом рецептов, как испечь собственного сервис-воркера.
- Workbox — это набор библиотек сервис-воркеров, созданных специально для создания прогрессивных веб-приложений.
- Запускаете ли вы рабочих серверов на CDN/Edge, например, для A/B-тестирования?
На данный момент мы уже привыкли запускать сервис-воркеры на клиенте, но с CDN, реализующими их на сервере, мы могли бы использовать их для настройки производительности и на периферии.Например, в A/B-тестах, когда HTML нужно менять содержимое для разных пользователей, мы могли бы использовать Service Workers на серверах CDN для обработки логики. Мы также могли бы транслировать переписывание HTML для ускорения работы сайтов, использующих Google Fonts.
- Оптимизация производительности рендеринга.
Всякий раз, когда приложение тормозит, это сразу заметно. Поэтому нам нужно убедиться, что при прокрутке страницы или при анимации элемента нет задержек, и что вы постоянно набираете 60 кадров в секунду. Если это невозможно, то, по крайней мере, сделать количество кадров в секунду согласованным предпочтительнее, чем смешанный диапазон от 60 до 15. Используйте CSSwill-change
, чтобы сообщить браузеру, какие элементы и свойства будут изменены.Всякий раз, когда вы испытываете, отлаживайте ненужные перерисовки в DevTools:
- Измеряйте производительность рендеринга во время выполнения. Ознакомьтесь с некоторыми полезными советами о том, как это понять.
- Для начала ознакомьтесь с бесплатным курсом Udacity Пола Льюиса по оптимизации рендеринга браузера и статьей Георгия Марчука «Отрисовка браузера и рекомендации по веб-производительности».
- Включите Paint Flashing в «Дополнительные инструменты → Рендеринг → Paint Flashing» в Firefox DevTools.
- В React DevTools установите флажок «Выделять обновления» и включите «Записывать, почему отображается каждый компонент».
- Вы также можете использовать Why Did You Render, чтобы при повторном рендеринге компонента вспышка уведомляла вас об изменении.
Вы используете макет Masonry? Имейте в виду, что очень скоро можно будет создать макет Masonry только с сеткой CSS.
Если вы хотите глубже погрузиться в тему, Нолан Лоусон поделился в своей статье приемами точного измерения производительности макета, а Джейсон Миллер также предложил альтернативные методы. У нас также есть небольшая статья Сергея Чикуёнка о том, как правильно сделать анимацию на GPU.
Примечание : изменения в слоях, созданных с помощью графического процессора, являются наименее затратными, поэтому, если вы можете уйти, запустив только композитинг с помощью
opacity
иtransform
, вы будете на правильном пути. Анна Мигас также дала много практических советов в своем выступлении на тему «Отладка производительности рендеринга пользовательского интерфейса». А чтобы понять, как отладить производительность рисования в DevTools, посмотрите видео аудита производительности рисования Умара. - Оптимизировали ли вы воспринимаемую производительность?
Хотя последовательность того, как компоненты отображаются на странице, и стратегия того, как мы обслуживаем ресурсы для браузера, имеют значение, мы также не должны недооценивать роль воспринимаемой производительности. Концепция касается психологических аспектов ожидания, в основном удерживая клиентов занятыми или вовлеченными, пока что-то еще происходит. Вот где в игру вступают управление восприятием, опережающее начало, раннее завершение и управление толерантностью.Что все это значит? При загрузке активов мы можем стараться всегда быть на шаг впереди клиента, поэтому работа кажется быстрой, в то время как в фоновом режиме происходит довольно много. Чтобы поддерживать интерес клиента, мы можем тестировать скелетные экраны (демонстрация реализации) вместо загрузки индикаторов, добавлять переходы/анимацию и фактически обманывать UX, когда больше нечего оптимизировать.
В своем тематическом исследовании The Art of UI Skeletons Кумар Макмиллан делится некоторыми идеями и методами моделирования динамических списков, текста и конечного экрана, а также того, как учитывать скелетное мышление с помощью React.
Однако будьте осторожны: скелетные экраны следует протестировать перед развертыванием, поскольку некоторые тесты показали, что каркасные экраны могут работать хуже всего по всем показателям.
- Предотвращаете ли вы смену макета и перерисовку?
В области воспринимаемой производительности, вероятно, одним из наиболее разрушительных событий является смещение макета или перекомпоновка , вызванное масштабированием изображений и видео, веб-шрифтов, внедренной рекламы или поздно обнаруженными скриптами, которые заполняют компоненты реальным контентом. В результате покупатель может начать читать статью только для того, чтобы его прервал скачок макета над областью чтения. Опыт часто бывает резким и довольно дезориентирующим: и это, вероятно, случай загрузки приоритетов, которые необходимо пересмотреть.Сообщество разработало несколько методов и обходных путей, чтобы избежать перекомпоновки. Как правило, рекомендуется избегать вставки нового контента поверх существующего , если только это не происходит в ответ на действия пользователя. Всегда устанавливайте атрибуты ширины и высоты для изображений, чтобы современные браузеры выделяли поле и резервировали пространство по умолчанию (Firefox, Chrome).
Как для изображений, так и для видео мы можем использовать заполнитель SVG, чтобы зарезервировать поле отображения, в котором будет отображаться медиафайл. Это означает, что область будет зарезервирована должным образом, когда вам также потребуется сохранить ее соотношение сторон. Мы также можем использовать заполнители или резервные изображения для рекламы и динамического контента, а также предварительно выделять слоты макета.
Вместо отложенной загрузки изображений с помощью внешних скриптов рассмотрите возможность использования встроенной отложенной загрузки или гибридной отложенной загрузки, когда мы загружаем внешний скрипт только в том случае, если собственная отложенная загрузка не поддерживается.
Как упоминалось выше, всегда группируйте перерисовки веб-шрифтов и переходите от всех резервных шрифтов ко всем веб-шрифтам одновременно — просто убедитесь, что этот переход не слишком резкий, регулируя высоту строки и расстояние между шрифтами с помощью font-style-matcher. .
Чтобы переопределить метрики шрифта для резервного шрифта для эмуляции веб-шрифта, мы можем использовать дескрипторы @font-face для переопределения метрик шрифта (демонстрация, включена в Chrome 87). (Обратите внимание, что настройки сложны со сложными стеками шрифтов.)
Для поздних версий CSS мы можем убедиться, что важные для макета CSS встроены в заголовок каждого шаблона. Более того: для длинных страниц при добавлении вертикальной полосы прокрутки основной контент смещается на 16 пикселей влево. Чтобы отобразить полосу прокрутки раньше, мы можем добавить
overflow-y: scroll
html
, чтобы принудительно использовать полосу прокрутки при первой отрисовке. Последнее помогает, потому что полосы прокрутки могут вызвать нетривиальные сдвиги макета из-за перекомпоновки содержимого верхней части сгиба при изменении ширины. В основном это должно происходить на платформах с полосами прокрутки без наложения, такими как Windows. Но: ломаетposition: sticky
, потому что эти элементы никогда не будут прокручиваться из контейнера.Если вы имеете дело с заголовками, которые становятся фиксированными или прилипают к верхней части страницы при прокрутке, зарезервируйте место для заголовка, когда он становится сосновым, например, с помощью элемента-заполнителя или
margin-top
в содержимом. Исключением должны быть баннеры согласия на использование файлов cookie, которые не должны влиять на CLS, но иногда влияют: это зависит от реализации. В этой ветке Твиттера есть несколько интересных стратегий и выводов.Для компонента вкладки, который может включать различное количество текстов, вы можете предотвратить смену макета с помощью стеков сетки CSS. Помещая содержимое каждой вкладки в одну и ту же область сетки и скрывая одну из них за раз, мы можем гарантировать, что контейнер всегда будет занимать высоту большего элемента, поэтому не произойдет смещения макета.
Ну, и, конечно же, бесконечная прокрутка и «Загрузить еще» также могут вызвать сдвиг макета, если под списком есть контент (например, нижний колонтитул). Чтобы улучшить CLS, зарезервируйте достаточно места для содержимого, которое будет загружено до того, как пользователь прокрутит страницу до этой части страницы, удалите нижний колонтитул или любые элементы DOM внизу страницы, которые могут быть сдвинуты вниз при загрузке содержимого. выполнять предварительную выборку данных и изображений для контента, расположенного ниже сгиба, чтобы к моменту, когда пользователь прокручивает до конца, он уже был там. Вы также можете использовать библиотеки виртуализации списков, такие как react-window, для оптимизации длинных списков ( спасибо, Эдди Османи! ).
Чтобы убедиться, что влияние перекомпоновки ограничено, измерьте стабильность макета с помощью API нестабильности макета. С его помощью вы можете рассчитать показатель Cumulative Layout Shift ( CLS ) и включить его в качестве требования в свои тесты, чтобы всякий раз, когда появляется регрессия, вы могли отслеживать ее и исправлять.
Чтобы рассчитать оценку сдвига макета, браузер смотрит на размер области просмотра и перемещение нестабильных элементов в области просмотра между двумя визуализируемыми кадрами. В идеале оценка должна быть близка к
0
. Существует отличное руководство Милицы Михайлии и Филипа Уолтона о том, что такое CLS и как его измерить. Это хорошая отправная точка для измерения и поддержания предполагаемой производительности и предотвращения сбоев, особенно для критически важных бизнес-задач.Небольшой совет : чтобы узнать, что вызвало изменение макета в DevTools, вы можете изучить изменения макета в разделе «Опыт» на панели «Производительность».
Бонус : если вы хотите уменьшить количество перекомпоновок и перерисовок, ознакомьтесь с руководством Чариса Теодулу по минимизации перекомпоновки/перераспределения макета DOM и списком Пола Айриша «Что заставляет разметку/перекомпоновку», а также с CSSTriggers.com, справочной таблицей свойств CSS, которые запускают разметку, рисование. и композитинга.
Сеть и HTTP/2
- Включено ли сшивание OCSP?
Включив сшивание OCSP на своем сервере, вы можете ускорить рукопожатия TLS. Протокол статуса онлайн-сертификатов (OCSP) был создан как альтернатива протоколу списка отзыва сертификатов (CRL). Оба протокола используются для проверки того, был ли отозван сертификат SSL.Однако протокол OCSP не требует, чтобы браузер тратил время на загрузку и последующий поиск в списке информации о сертификате, что сокращает время, необходимое для рукопожатия.
- Уменьшили ли вы влияние отзыва SSL-сертификата?
В своей статье «Стоимость сертификатов EV» Саймон Хирн дает отличный обзор распространенных сертификатов и влияние выбора сертификата на общую производительность.Как пишет Саймон, в мире HTTPS существует несколько типов уровней проверки сертификатов, используемых для защиты трафика:
- Проверка домена (DV) подтверждает, что инициатор запроса сертификата владеет доменом,
- Проверка организации (OV) подтверждает, что организация владеет доменом,
- Расширенная проверка (EV) подтверждает, что организация владеет доменом, с тщательной проверкой.
Важно отметить, что все эти сертификаты одинаковы с точки зрения технологии; они отличаются только информацией и свойствами, указанными в этих сертификатах.
Сертификаты EV дороги и требуют много времени , поскольку они требуют, чтобы человек просматривал сертификат и гарантировал его действительность. Сертификаты DV, с другой стороны, часто предоставляются бесплатно — например, Let's Encrypt — открытым автоматизированным центром сертификации, хорошо интегрированным со многими хостинг-провайдерами и CDN. Фактически, на момент написания статьи он поддерживает более 225 миллионов веб-сайтов (PDF), хотя он составляет только 2,69% страниц (открытых в Firefox).
Так в чем же тогда проблема? Проблема в том, что сертификаты EV не полностью поддерживают упомянутое выше сшивание OCSP . В то время как сшивание позволяет серверу проверить с центром сертификации, был ли сертификат отозван, а затем добавить («сшивать») эту информацию в сертификат, без сшивания всю работу должен выполнять клиент, что приводит к ненужным запросам во время согласования TLS. . При плохом соединении это может привести к заметным потерям производительности (1000 мс+).
Сертификаты EV не лучший выбор для веб-производительности, и они могут оказать гораздо большее влияние на производительность, чем сертификаты DV. Для оптимальной производительности Интернета всегда используйте сшитый DV-сертификат OCSP. Они также намного дешевле, чем сертификаты EV, и их проще приобрести. Ну, по крайней мере, пока не появится CRLite.
Примечание . При использовании QUIC/HTTP/3 стоит отметить, что цепочка сертификатов TLS — это единственный контент переменного размера, который доминирует в подсчете байтов в рукопожатии QUIC. Размер варьируется от нескольких сотен байтов до более 10 КБ.
Таким образом, небольшие сертификаты TLS имеют большое значение для QUIC/HTTP/3, так как большие сертификаты вызовут несколько рукопожатий. Кроме того, нам нужно убедиться, что сертификаты сжаты, иначе цепочки сертификатов будут слишком большими, чтобы поместиться в одну сборку QUIC.
Вы можете найти более подробную информацию и указатели на проблему и решения на:
- Сертификаты EV делают Интернет медленным и ненадежным Аарон Питерс,
- Влияние отзыва SSL-сертификата на производительность сети, Мэтт Хоббс,
- Стоимость сертификатов EV Саймона Херна,
- Требует ли рукопожатие QUIC быстрого сжатия? Патрик Макманус.
- Вы уже приняли IPv6?
Поскольку у нас заканчивается пространство с IPv4, а основные мобильные сети быстро внедряют IPv6 (США почти достигли 50-процентного порога внедрения IPv6), рекомендуется обновить DNS до IPv6, чтобы оставаться пуленепробиваемым в будущем. Просто убедитесь, что в сети предоставляется поддержка двойного стека — это позволяет IPv6 и IPv4 работать одновременно друг с другом. В конце концов, IPv6 не поддерживает обратную совместимость. Кроме того, исследования показывают, что IPv6 сделал эти веб-сайты на 10–15% быстрее благодаря обнаружению соседей (NDP) и оптимизации маршрутов. - Убедитесь, что все активы работают через HTTP/2 (или HTTP/3).
Поскольку в последние несколько лет Google стремится к более безопасной сети HTTPS, переход на среду HTTP/2, безусловно, является хорошей инвестицией. На самом деле, согласно веб-альманаху, 64% всех запросов уже выполняются через HTTP/2.Важно понимать, что HTTP/2 не идеален и имеет проблемы с приоритизацией, но поддерживается очень хорошо; и, в большинстве случаев, вам лучше с ним.
Предостережение: HTTP/2 Server Push удаляется из Chrome, поэтому, если ваша реализация полагается на Server Push, возможно, вам придется вернуться к нему. Вместо этого мы могли бы рассмотреть ранние подсказки, которые уже интегрированы в качестве эксперимента в Fastly.
Если вы все еще работаете с HTTP, наиболее трудоемкой задачей будет сначала перейти на HTTPS, а затем настроить процесс сборки для поддержки мультиплексирования и распараллеливания HTTP/2. Внедрение HTTP/2 в Gov.uk — это фантастический пример того, как сделать именно это, попутно найдя путь через CORS, SRI и WPT. В оставшейся части этой статьи мы предполагаем, что вы либо переходите на HTTP/2, либо уже переключились на него.
- Правильно разверните HTTP/2.
Опять же, обслуживание ресурсов через HTTP/2 может выиграть от частичного пересмотра того, как вы обслуживали ресурсы до сих пор. Вам нужно будет найти тонкий баланс между упаковкой модулей и параллельной загрузкой множества небольших модулей. В конце концов, лучший запрос — это отсутствие запроса, однако цель состоит в том, чтобы найти баланс между быстрой первой доставкой ресурсов и кэшированием.С одной стороны, вы, возможно, захотите вообще избежать конкатенации ресурсов, вместо того, чтобы разбивать весь интерфейс на множество небольших модулей, сжимая их как часть процесса сборки и загружая их параллельно. Изменение в одном файле не потребует повторной загрузки всей таблицы стилей или JavaScript. Это также сводит к минимуму время синтаксического анализа и снижает нагрузку на отдельные страницы.
С другой стороны, упаковка по-прежнему имеет значение. При использовании большого количества небольших сценариев страдает общее сжатие и увеличивается стоимость извлечения объектов из кэша. Сжатие большого пакета выиграет от повторного использования словаря, в то время как небольшие отдельные пакеты этого не сделают. Есть стандартная работа по решению этой проблемы, но пока это далеко не так. Во-вторых, браузеры еще не оптимизированы для таких рабочих процессов. Например, Chrome будет запускать межпроцессное взаимодействие (IPC) линейно в зависимости от количества ресурсов, поэтому включение сотен ресурсов будет иметь затраты времени выполнения браузера.
Тем не менее, вы можете попробовать загружать CSS постепенно. На самом деле встроенный CSS больше не блокирует рендеринг для Chrome. Но есть некоторые проблемы с расстановкой приоритетов, так что это не так просто, но с ними стоит поэкспериментировать.
Вы можете обойтись без объединения соединений HTTP/2, что позволяет вам использовать сегментирование домена, получая преимущества от HTTP/2, но добиться этого на практике сложно, и в целом это не считается хорошей практикой. Кроме того, HTTP/2 и целостность субресурсов не всегда ладят.
Что делать? Что ж, если вы используете HTTP/2, отправка примерно 6–10 пакетов кажется достойным компромиссом (и не так уж плохо для устаревших браузеров). Экспериментируйте и измеряйте, чтобы найти правильный баланс для вашего сайта.
- Отправляем ли мы все активы через одно соединение HTTP/2?
Одним из основных преимуществ HTTP/2 является то, что он позволяет нам отправлять активы по сети через одно соединение. Однако иногда мы могли сделать что-то не так — например, иметь проблему с CORS или неправильно настроить атрибутcrossorigin
, поэтому браузер был вынужден открыть новое соединение.Чтобы проверить, используют ли все запросы одно соединение HTTP/2 или что-то неправильно настроено, включите столбец «Идентификатор соединения» в DevTools → Network. Например, здесь все запросы используют одно и то же соединение (286), кроме manifest.json, который открывает отдельное соединение (451).
- Поддерживают ли ваши серверы и CDN HTTP/2?
Разные серверы и CDN (по-прежнему) по-разному поддерживают HTTP/2. Используйте сравнение CDN, чтобы проверить свои варианты или быстро узнать, как работают ваши серверы и какие функции вы можете рассчитывать на поддержку.Проконсультируйтесь с невероятным исследованием Пэта Минана о приоритетах HTTP/2 (видео) и проверьте поддержку сервера для приоритизации HTTP/2. По словам Пэта, рекомендуется включить контроль перегрузки BBR и установить для
tcp_notsent_lowat
значение 16 КБ, чтобы приоритизация HTTP/2 надежно работала на ядрах Linux 4.9 и более поздних версиях ( спасибо, Йоав! ). Энди Дэвис провел аналогичное исследование для определения приоритетов HTTP/2 в браузерах, CDN и службах облачного хостинга.Находясь на нем, дважды проверьте, поддерживает ли ваше ядро TCP BBR, и включите его, если это возможно. В настоящее время он используется на Google Cloud Platform, Amazon Cloudfront, Linux (например, Ubuntu).
- Используется ли сжатие HPACK?
Если вы используете HTTP/2, убедитесь, что ваши серверы используют сжатие HPACK для заголовков ответа HTTP, чтобы уменьшить ненужные накладные расходы. Некоторые серверы HTTP/2 могут не полностью поддерживать спецификацию, например, HPACK. H2spec — отличный (хотя и очень технически подробный) инструмент для проверки этого. Алгоритм сжатия HPACK впечатляет, и он работает. - Убедитесь, что безопасность вашего сервера пуленепробиваема.
Все браузерные реализации HTTP/2 работают через TLS, поэтому вы, вероятно, захотите избежать предупреждений безопасности или неработающих элементов на вашей странице. Дважды проверьте правильность настройки заголовков безопасности, устраните известные уязвимости и проверьте настройку HTTPS.Кроме того, убедитесь, что все внешние подключаемые модули и сценарии отслеживания загружаются через HTTPS, что межсайтовые сценарии невозможны и что заголовки HTTP Strict Transport Security и заголовки Content Security Policy установлены правильно.
- Поддерживают ли ваши серверы и CDN HTTP/3?
Хотя HTTP/2 принес ряд значительных улучшений производительности в Интернете, он также оставил немало возможностей для улучшения — особенно блокировку начала строки в TCP, которая была заметна в медленной сети со значительной потерей пакетов. HTTP/3 решает эти проблемы навсегда (статья).Для решения проблем HTTP/2 IETF вместе с Google, Akamai и другими работает над новым протоколом, который недавно был стандартизирован как HTTP/3.
Робин Маркс очень хорошо объяснил HTTP/3, и следующее объяснение основано на его объяснении. По своей сути HTTP/3 очень похож на HTTP/2 с точки зрения функций, но внутри он работает совсем по-другому. HTTP/3 предоставляет ряд улучшений: более быстрые рукопожатия, лучшее шифрование, более надежные независимые потоки, лучшее шифрование и управление потоком. Заметным отличием является то, что HTTP/3 использует QUIC в качестве транспортного уровня, при этом пакеты QUIC инкапсулируются поверх диаграмм UDP, а не TCP.
QUIC полностью интегрирует TLS 1.3 в протокол, в то время как в TCP он находится поверх. В типичном стеке TCP у нас есть несколько накладных расходов, поскольку TCP и TLS должны выполнять свои собственные отдельные рукопожатия, но с QUIC оба они могут быть объединены и завершены всего за один цикл . Поскольку TLS 1.3 позволяет нам устанавливать ключи шифрования для последующего соединения, начиная со второго соединения, мы уже можем отправлять и получать данные прикладного уровня в первом круговом цикле, который называется «0-RTT».
Кроме того, алгоритм сжатия заголовков HTTP/2 был полностью переписан вместе с его системой приоритетов. Кроме того, QUIC поддерживает перенос соединения с Wi-Fi на сотовую сеть с помощью идентификаторов соединения в заголовке каждого пакета QUIC. Большинство реализаций выполняются в пространстве пользователя, а не в пространстве ядра (как это делается с TCP), поэтому следует ожидать, что протокол будет развиваться в будущем.
Будет ли все это иметь большое значение? Вероятно, да, особенно это влияет на время загрузки на мобильных устройствах, а также на то, как мы обслуживаем ресурсы для конечных пользователей. В то время как в HTTP/2 несколько запросов совместно используют соединение, в HTTP/3 запросы также используют соединение, но потоки независимы, поэтому отброшенный пакет больше не влияет на все запросы, а только на один поток.
Это означает, что хотя с одним большим пакетом JavaScript обработка ресурсов будет замедляться, когда один поток приостанавливается, влияние будет менее значительным, когда несколько файлов передаются параллельно (HTTP/3). Так что упаковка по-прежнему имеет значение .
Работа над HTTP/3 все еще продолжается. Chrome, Firefox и Safari уже имеют реализации. Некоторые CDN уже поддерживают QUIC и HTTP/3. В конце 2020 года Chrome начал развертывание HTTP/3 и IETF QUIC, и фактически все сервисы Google (Google Analytics, YouTube и т. д.) уже работают по протоколу HTTP/3. Веб-сервер LiteSpeed поддерживает HTTP/3, но ни Apache, ни nginx, ни IIS пока не поддерживают его, но, вероятно, в 2021 году это быстро изменится.
Вывод : если у вас есть возможность использовать HTTP/3 на сервере и в CDN, вероятно, это очень хорошая идея. Основное преимущество будет заключаться в одновременном получении нескольких объектов, особенно при соединениях с высокой задержкой. Мы еще не знаем наверняка, так как в этой области не проводилось много исследований, но первые результаты очень многообещающие.
Если вы хотите больше узнать о специфике и преимуществах протокола, вот несколько хороших отправных точек для проверки:
- Объяснение HTTP/3, совместная работа по документированию протоколов HTTP/3 и QUIC. Доступно на разных языках, а также в формате PDF.
- Повышение веб-производительности с помощью HTTP/3 с Дэниелом Стенбергом.
- Академическое руководство по QUIC с Робином Марксом знакомит с основными понятиями протоколов QUIC и HTTP/3, объясняет, как HTTP/3 обрабатывает блокировку заголовка строки и миграцию соединений, а также как HTTP/3 разработан, чтобы быть вечнозеленым (спасибо, Саймон !).
- Вы можете проверить, работает ли ваш сервер на HTTP/3 на HTTP3Check.net.
Тестирование и мониторинг
- Оптимизировали ли вы свой рабочий процесс аудита?
Это может показаться не таким уж большим делом, но наличие правильных настроек под рукой может сэкономить вам немало времени при тестировании. Рассмотрите возможность использования рабочего процесса Альфреда Тима Кадлека для WebPageTest для отправки теста в общедоступный экземпляр WebPageTest. На самом деле, в WebPageTest есть много неясных функций, поэтому найдите время, чтобы научиться читать диаграмму WebPageTest Waterfall View и как читать диаграмму WebPageTest Connection View, чтобы быстрее диагностировать и решать проблемы с производительностью.Вы также можете запустить WebPageTest из электронной таблицы Google и включить показатели доступности, производительности и SEO в свою настройку Travis с помощью Lighthouse CI или прямо в Webpack.
Взгляните на недавно выпущенный модульный инструмент AutoWebPerf, который позволяет автоматически собирать данные о производительности из нескольких источников. Например, мы можем провести ежедневный тест на ваших критически важных страницах, чтобы получить полевые данные из CrUX API и лабораторные данные из отчета Lighthouse из PageSpeed Insights.
И если вам нужно что-то быстро отладить, но ваш процесс сборки кажется удивительно медленным, имейте в виду, что «удаление пробелов и изменение символов составляет 95% уменьшения размера минимизированного кода для большинства JavaScript, а не сложные преобразования кода. Вы можете просто отключите сжатие, чтобы ускорить сборку Uglify в 3-4 раза».
- Вы тестировали в прокси-браузерах и устаревших браузерах?
Тестирования в Chrome и Firefox недостаточно. Посмотрите, как ваш сайт работает в прокси-браузерах и устаревших браузерах. UC Browser и Opera Mini, например, занимают значительную долю рынка в Азии (до 35% в Азии). Измерьте среднюю скорость Интернета в интересующих вас странах, чтобы избежать больших сюрпризов в будущем. Протестируйте с регулированием скорости сети и эмулируйте устройство с высоким разрешением. BrowserStack отлично подходит для тестирования на удаленных реальных устройствах, и дополните его хотя бы несколькими реальными устройствами в вашем офисе — оно того стоит.
- Вы проверяли производительность своих 404 страниц?
Обычно мы не думаем дважды, когда дело доходит до 404 страниц. В конце концов, когда клиент запрашивает страницу, которой нет на сервере, сервер ответит кодом состояния 404 и соответствующей страницей 404. Там не так уж много, не так ли?Важным аспектом ответов 404 является фактический размер тела ответа , отправляемого в браузер. Согласно исследованию 404 страниц, проведенному Мэттом Хоббсом, подавляющее большинство ответов 404 исходит от отсутствующих фавиконов, запросов на загрузку WordPress, неработающих запросов JavaScript, файлов манифеста, а также файлов CSS и шрифтов. Каждый раз, когда клиент запрашивает несуществующий актив, он получает ответ 404 — и часто этот ответ огромен.
Обязательно изучите и оптимизируйте стратегию кэширования для своих страниц 404. Наша цель — предоставлять HTML браузеру только тогда, когда он ожидает HTML-ответ, и возвращать небольшую полезную нагрузку с ошибкой для всех остальных ответов. По словам Мэтта, «если мы разместим CDN перед нашим источником, у нас будет возможность кэшировать ответ страницы 404 в CDN. Это полезно, потому что без этого попадание на страницу 404 может быть использовано как вектор атаки DoS, путем заставляя исходный сервер отвечать на каждый запрос 404 вместо того, чтобы позволить CDN отвечать кэшированной версией».
Ошибки 404 могут не только снизить производительность, но и снизить трафик, поэтому рекомендуется включить страницу ошибки 404 в набор тестирования Lighthouse и отслеживать ее оценку с течением времени.
- Проверяли ли вы эффективность своих запросов согласия GDPR?
Во времена GDPR и CCPA стало обычным делом полагаться на третьих лиц, чтобы предоставить клиентам из ЕС варианты выбора или отказа от отслеживания. Однако, как и в случае с любым другим сторонним скриптом, их производительность может иметь разрушительное влияние на общую производительность.Конечно, фактическое согласие, вероятно, изменит влияние сценариев на общую производительность, поэтому, как заметил Борис Шапира, мы могли бы изучить несколько различных профилей веб-производительности:
- В согласии было полностью отказано,
- В согласии частично отказано,
- Согласие было дано полностью.
- Пользователь не отреагировал на запрос согласия (или запрос был заблокирован блокировщиком контента),
Обычно запросы согласия на использование файлов cookie не должны влиять на CLS, но иногда они влияют, поэтому рассмотрите возможность использования бесплатных опций с открытым исходным кодом Osano или cookie-consent-box.
В общем, стоит изучить производительность всплывающих окон, так как вам нужно будет определить горизонтальное или вертикальное смещение события мыши и правильно расположить всплывающее окно относительно точки привязки. Ноам Розенталь делится знаниями команды Викимедиа в статье «Пример веб-производительности: предварительный просмотр страниц Википедии» (также доступен в виде видео и минут).
- Ведете ли вы CSS для диагностики производительности?
Хотя мы можем включить все виды проверок, чтобы гарантировать, что непроизводительный код будет развернут, часто бывает полезно получить быстрое представление о некоторых низко висящих плодах, которые можно легко решить. Для этого мы могли бы использовать великолепный CSS для диагностики производительности Тима Кадлека (вдохновленный фрагментом кода Гарри Робертса, который выделяет изображения с отложенной загрузкой, изображения без размера, изображения в устаревшем формате и синхронные сценарии.Например, вы можете захотеть убедиться, что никакие изображения над сгибом не загружаются лениво. Вы можете настроить фрагмент под свои нужды, например, выделить неиспользуемые веб-шрифты или определить шрифты значков. Отличный небольшой инструмент для обеспечения видимости ошибок во время отладки или просто для очень быстрого аудита текущего проекта.
/* Performance Diagnostics CSS */ /* via Harry Roberts. https://twitter.com/csswizardry/status/1346477682544951296 */ img[loading=lazy] { outline: 10px solid red; }
- Вы проверили влияние на доступность?
Когда браузер начинает загружать страницу, он строит DOM, а если есть вспомогательные технологии, такие как программа чтения с экрана, он также создает дерево специальных возможностей. Затем программа чтения с экрана должна запросить дерево специальных возможностей, чтобы получить информацию и сделать ее доступной для пользователя — иногда по умолчанию, а иногда по требованию. А иногда это требует времени.Говоря о быстром времени до интерактивности, обычно мы имеем в виду показатель того, как скоро пользователь может взаимодействовать со страницей, щелкая или нажимая на ссылки и кнопки. Контекст немного отличается от средств чтения с экрана. В этом случае быстрое время до интерактивности означает, сколько времени проходит, пока программа чтения с экрана не сможет объявить о переходе по данной странице, а пользователь программы чтения с экрана не сможет фактически нажать клавиатуру для взаимодействия.
Леони Уотсон выступила с откровенным докладом о производительности специальных возможностей и, в частности, о влиянии медленной загрузки на задержки объявлений программ чтения с экрана. Программы чтения с экрана привыкли к быстро меняющимся объявлениям и быстрой навигации, поэтому потенциально могут быть даже менее терпеливыми, чем зрячие пользователи.
Большие страницы и манипуляции с DOM с помощью JavaScript вызовут задержки в объявлениях программ чтения с экрана. Довольно неисследованная область, которая требует некоторого внимания и тестирования, так как программы чтения с экрана доступны буквально на каждой платформе (Jaws, NVDA, Voiceover, Narrator, Orca).
- Настроен ли постоянный мониторинг?
Наличие частного экземпляра WebPagetest всегда полезно для быстрых и неограниченных тестов. Однако инструмент непрерывного мониторинга, такой как Sitespeed, Caliber и SpeedCurve, с автоматическими оповещениями даст вам более подробную картину вашей производительности. Установите собственные временные метки пользователя, чтобы измерять и отслеживать специфические для бизнеса показатели. Кроме того, рассмотрите возможность добавления автоматических предупреждений о снижении производительности, чтобы отслеживать изменения с течением времени.Рассмотрите возможность использования RUM-решений для отслеживания изменений производительности с течением времени. Для автоматизированных инструментов нагрузочного тестирования, подобных модульному тестированию, вы можете использовать k6 с его API сценариев. Также обратите внимание на SpeedTracker, Lighthouse и Calibre.
Быстрые победы
Этот список довольно обширен, и выполнение всех оптимизаций может занять некоторое время. Итак, если бы у вас был всего 1 час, чтобы добиться значительных улучшений, что бы вы сделали? Давайте сведем все это к 17 низко висящим фруктам . Очевидно, что перед тем, как вы начнете и закончите, измерьте результаты, включая «Максимальное отрисовку контента» и «Время до интерактивности» при 3G- и кабельном соединении.
- Измеряйте реальный мировой опыт и ставьте соответствующие цели. Стремитесь быть как минимум на 20% быстрее, чем ваш самый быстрый конкурент. Оставайтесь в пределах максимального содержания контента < 2,5 с, задержка первого ввода < 100 мс, время до взаимодействия < 5 с на медленном 3G, для повторных посещений, TTI < 2 с. Оптимизируйте хотя бы для First Contentful Paint и Time To Interactive.
- Оптимизируйте изображения с помощью Squoosh, mozjpeg, guetzli, pingo и SVGOMG и подавайте AVIF/WebP с CDN изображений.
- Подготовьте важный CSS для ваших основных шаблонов и вставьте их в
<head>
каждого шаблона. Для CSS/JS работайте в пределах критического бюджета размера файла макс. 170 КБ в сжатом виде (0,7 МБ в распакованном виде). - Обрезайте, оптимизируйте, откладывайте и лениво загружайте скрипты. Инвестируйте в конфигурацию вашего сборщика, чтобы удалить избыточность и проверить облегченные альтернативы.
- Всегда размещайте свои статические ресурсы самостоятельно и всегда предпочитайте самостоятельно размещать сторонние ресурсы. Ограничьте влияние сторонних скриптов. Используйте фасады, загружайте виджеты при взаимодействии и остерегайтесь антимерцающих фрагментов.
- Будьте избирательны при выборе фреймворка. Для одностраничных приложений идентифицируйте критические страницы и обслуживайте их статически или, по крайней мере, предварительно визуализируйте их, а также используйте прогрессивную гидратацию на уровне компонентов и импортируйте модули при взаимодействии.
- Рендеринг на стороне клиента сам по себе не является хорошим выбором для повышения производительности. Сделайте предварительный рендеринг, если ваши страницы не сильно меняются, и отложите загрузку фреймворков, если можете. Если возможно, используйте потоковый рендеринг на стороне сервера.
- Предоставляйте устаревший код только устаревшим браузерам с
<script type="module">
и шаблоном module/nomodule. - Поэкспериментируйте с перегруппировкой правил CSS и протестируйте встроенный CSS.
- Добавьте подсказки ресурсов, чтобы ускорить доставку с помощью более быстрого
dns-lookup
,preconnect
,prefetch
,preload
иprerender
. - Подмножьте веб-шрифты и загрузите их асинхронно, а также используйте
font-display
в CSS для быстрого первого рендеринга. - Убедитесь, что заголовки кэша HTTP и заголовки безопасности установлены правильно.
- Включите сжатие Brotli на сервере. (Если это невозможно, по крайней мере, убедитесь, что сжатие Gzip включено.)
- Включите перегрузку TCP BBR, если ваш сервер работает на ядре Linux версии 4.9+.
- Включите сшивание OCSP и IPv6, если это возможно. Всегда обслуживайте сертификат DV, скрепленный скобками OCSP.
- Включите сжатие HPACK для HTTP/2 и перейдите на HTTP/3, если он доступен.
- Кэшируйте активы, такие как шрифты, стили, JavaScript и изображения, в кэше сервис-воркера.
Скачать контрольный список (PDF, Apple Pages)
Имея в виду этот контрольный список, вы должны быть готовы к любому проекту производительности внешнего интерфейса. Не стесняйтесь загружать готовый к печати PDF-файл контрольного списка, а также редактируемый документ Apple Pages , чтобы настроить контрольный список в соответствии с вашими потребностями:
- Скачать контрольный список в формате PDF (PDF, 166 КБ)
- Загрузить контрольный список в Apple Pages (.pages, 275 КБ)
- Скачать чек-лист в формате MS Word (.docx, 151 КБ)
Если вам нужны альтернативы, вы также можете проверить контрольный список внешнего интерфейса Дэна Рублика, «Контрольный список веб-производительности дизайнера» Джона Яблонски и Контрольный список внешнего интерфейса.
Поехали!
Некоторые из оптимизаций могут выходить за рамки вашей работы или бюджета или могут быть просто излишними, учитывая устаревший код, с которым вам приходится иметь дело. Хорошо! Используйте этот контрольный список в качестве общего (и, надеюсь, исчерпывающего) руководства и создайте собственный список проблем, которые применимы к вашему контексту. Но самое главное, протестируйте и измерьте свои собственные проекты, чтобы выявить проблемы перед оптимизацией. Всем удачных результатов в 2021 году!
Огромное спасибо Гаю Подярному, Йоаву Вайсу, Эдди Османи, Артему Денисову, Денису Мишунову, Илье Пухальски, Джереми Вагнеру, Колину Бенделлу, Марку Земану, Патрику Минану, Леонардо Лосовизу, Энди Дэвису, Рэйчел Эндрю, Ансельму Ханнеманну, Барри Полларду, Патрику. Хаманн, Гидеон Пайзер, Энди Дэвис, Мария Просвернина, Тим Кадлек, Рей Банго, Матиас Отт, Питер Бойер, Фил Уолтон, Мариана Перальта, Пепейн Сендерс, Марк Ноттингем, Жан Пьер Винсент, Филипп Теллис, Райан Таунсенд, Ингрид Бергман, Мохамед Хуссейн SH, Джейкобу Гроссу, Тиму Сваллингу, Бобу Виссеру, Кеву Адамсону, Адиру Амсалему, Алексею Куликову и Родни Рему за рецензирование этой статьи, а также нашему фантастическому сообществу, которое поделилось методами и уроками, извлеченными из своей работы по оптимизации производительности для всех. . Вы действительно сокрушительны!