Skip to content

Latest commit

 

History

History

the-critical-request

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

Критический запрос

Перевод статьи Ben Schwarz: The Critical Request.

Отдать веб-сайт кажется довольно простой задачей: отправьте HTML-код, а браузер уже поймёт, какие ресурсы нужно загрузить дальше. Затем мы терпеливо ожидаем, пока страница будет готова.

Но мало кто знает, сколь многое происходит под капотом.

Вы когда-нибудь задумывались, как браузер определяет, какие ресурсы следует запрашивать и в каком порядке?

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

Приоритет ресурсов в работе

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

В Chrome сегодня существует ряд уровней приоритизации ресурсов: очень низкий, низкий, средний, высокий и очень высокий (Very Low, Low, Medium, High and Very high). Если заглянуть в исходники Chrome DevTools, то можно заметить, что эти псевдонимы имеют несколько иные метки: Lowest, Low, Medium, High и Highest.

Чтобы узнать, как ваш браузер приоритизирует запросы, вы можете включить столбец приоритета в таблице сетевых запросов Chrome DevTools.

Эй! Если вы используете Safari Technology превью, столбец приоритета (новый!) можно включить точно так же.

Включите столбец «Priority» правым кликом по любому из заголовков таблицы запросов

Вы также найдете приоритет для выбранного запроса на вкладке «Performance».

Тайминги и приоритеты ресурса отображаются при наведении

Как Chrome приоритизирует ресурсы?

Каждый тип ресурса (CSS, JavaScript, шрифты и так далее) имеет свой собственный набор правил, определяющий, как он будет приоритизирован. Ниже приведён неполный список планов сетевого приоритета:

HTML — высочайший приоритет (Highest).

Стили — высочайший приоритет (Highest). Стили, на которые есть ссылки с помощью директивы @import, также получат приоритет Highest, но они будут поставлены в очередь после блокировки скриптов.

Изображения являются единственными ресурсами, чей приоритет может варьироваться на основе эвристики вьюпорта. Все изображения начинают с приоритета Low, но в момент отображения в видимом вьюпорте их приоритет будет обновлён до Medium. Изображения за пределами вьюпорта (также называемые «скрытыми») останутся с низким приоритетом.

Во время исследований для этой статьи я обнаружил (с помощью Пола Айриша), что Chrome DevTools в настоящее время неправильно отображают приоритет изображений, которые были обновлены до уровня Medium (они остаются на уровне Low). Пол написал багрепорт, за статусом которого вы можете наблюдать здесь.

Если вам интересно почитать исходники Chrome, обновляющих приоритет загрузки изображений, начните с UpdateAllImageResourcePriorities и ComputeResourcePriority.

Ajax/XHR/fetch() — высокий приоритет (High).

Скрипты используют сложную схему приоритизации загрузки. (Джейк Арчибальд подробно об этом писал в 2013 году. Если вы хотите узнать больше, я предлагаю вам взять чашечку чая и погрузиться в чтение). TL;DR:

  • Скрипты, загруженные с помощью <script src="name.js"></script>, будут иметь приоритет High, если они появляются в разметке перед изображением.
  • Скрипты, загруженные с помощью <script src="name.js"></script>, будут иметь приоритет Medium, если они появляются в разметке после изображения.
  • Скрипты, использующие атрибуты async или defer, получат приоритет Low.
  • Скрипты, использующие type="module" получат приоритет Low.

Шрифты - это немного странное существо: они являются очень важным ресурсом (кто из вас любит игру «Я вижу это!», «Теперь не вижу», «Ура, новый шрифт!»?). Поэтому в том, что шрифты загружаются с приоритетом Highest, смысл есть.

К сожалению, большинство правил @font-face находятся во внешних файлах стилей (загружаются с помощью чего-то вроде: <link rel="stylesheet" href="file.css">). Это означает, что веб-шрифты обычно задерживаются до тех пор, пока файл стилей не будет загружен.

Даже если ваш CSS-файл ссылается на шрифт @font-face, он не будет запрашиваться до тех пор, пока этот шрифт не будет использован в селекторе, а этот селектор будет соответствовать элементу на странице. Если вы создали одностраничное приложение, которое не отображает текст до тех пор, пока оно не будет отрендерено, вы ещё больше задержите шрифты.

Что делает запрос критичным?

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

То, что браузер не будет делать более 6 одновременных запросов на домен, в прошлом разработчики обходили, используя хосты вида assets-1.domain.tld, assets-2.domain.tld, чтобы увеличить количество асинхронных загрузок, но часто не осознавали, что для каждого нового домена и ресурса будет вызываться DNS-запрос и создаваться новое TCP-соединение.

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

К счастью, сегодня у нас есть отличные инструменты. Используя CNN в качестве примера, давайте определим ресурсы, которые абсолютно необходимы для того, чтобы вьюпорт визуально был готов (иначе говоря, стал полезным для того, кто пытается его прочитать).

Критически важным для пользователя контентом являются шапка и заглавная статья

Для отображения этого экрана действительно нужно всего 5 вещей (и не все они должны быть загружены до того, как сайт будет использоваться):

  • Самое главное - HTML. Если все остальное провалится, пользователь все равно может прочитать страницу.
  • CSS
  • Логотип (background-image PNG, помещённое в CSS. Возможно, это может быть встроенный SVG).
  • 4(!) начертания веб-шрифтов.
  • Изображение для заглавной статьи.

Эти ресурсы (обратите внимание на отсутствие JavaScript) необходимы для визуала, составляющего основной вьюпорт страницы. Эти ресурсы должны быть загружены первыми.

Если заглянуть в панель Performance в Chrome, то можно увидеть, что около 50 запросов выполняются до того, как запрашиваются шрифты и изображение.

CNN.com полностью отображается где-то через 9 секунд. Это было записано с использованием 4G-соединения с умеренно разнородным покрытием.

Существует чёткое несоответствие между запросами, необходимыми для отображения, и фактически выполняемыми запросами.

Управление приоритетами ресурсов

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

Прелоад (<link rel="preload" href="font.woff" as="font" />) указывает браузеру, что необходимо добавить font.woff в очередь загрузок с приоритетом «High».

Примечание: as="font" - причина, по которой font.woff будет загружаться с высоким приоритетом. Это шрифт, поэтому он следует плану приоритетов, рассмотренному ранее в разделе «Как Chrome приоритизирует ресурсы?».

По сути, вы говорите браузеру: возможно, ты этого ещё не знаешь, но нам это понадобится.

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

  • Мы ожидаем, что CSS будет загружен, проанализирован и применён до того, как будут обнаружены правила @font-face.
  • Шрифт не добавляется в очередь загрузок браузера до тех пор, пока не сработают его CSS-правила на DOM с помощью селекторов.
  • Этот матчинг CSS-правила на DOM происходит во время пересчёта стилей. Это не обязательно происходит сразу после загрузки и может быть отложено, если основной поток занят.

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

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

Предварительная загрузка в действии: шрифты

Я провёл два теста на calibreapp.com. На первом запуске я вообще ничего не изменил в сайте. Во втором я добавил эти два тега:

<link rel="preload" as="font" href="Calibre-Regular.woff2" type="font/woff2" crossorigin />
<link rel="preload" as="font" href="Calibre-Semibold.woff2" type="font/woff2" crossorigin />

Ниже вы увидите визуальное сравнение рендеринга этих двух тестов. Результаты довольно ошеломляющие:

Страница отрендерилась на 3,5 секунды быстрее, когда шрифты были предварительно загружены.

Внизу: шрифты предварительно загружены. Сайт завершает рендеринг через 5 секунд на 3G-соединении уровня «развивающихся рынков».

<link rel="preload"> также принимает атрибут media="", который выборочно приоритизирует ресурсы на основе правил @media-запроса:

<link rel="preload" href="article-lead-sm.jpg" as="image" type="image/jpeg" media="only screen and (max-width: 48rem)">

Здесь мы можем предварительно загрузить определенное изображение для устройств с маленькими экранами. Идеально подходит для «изображения главного героя».

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

Сложная доставка веб-шрифтов

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

Честно говоря, этот отстой почти на каждом уровне.

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

Мы можем сделать дальнейшие улучшения, используя CSS-свойство font-display. Оно позволяет нам контролировать как отображаются шрифты во время запроса и загрузки веб-шрифтов.

В вашем распоряжении 4 варианта, но я бы предложил использовать font-display: swap;, который покажет резервный шрифт до окончания загрузки веб-шрифта - в этот момент он будет заменён.

Учитывая такой стек шрифтов,

body {
  font-family: Calibre, Helvetica, Arial;
}

браузер отобразит Helvetica (или Arial, если у вас нет Helvetica), пока не загрузится шрифт Caliber. Сейчас Chrome и Opera являются единственными браузерами, поддерживающими font-display, но это шаг вперёд и нет оснований не использовать его, начиная с сегодняшнего дня.

Сохранение производительности страницы

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

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

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

  • Первое отображение (First paint) сообщает нам, когда браузер переходит от «ничего к чему-то».
  • Первое значимое отображение (First meaningful paint) говорит нам, что браузер «сделал что-то полезное».
  • Наконец, первая интерактивность (First Interactive) сообщает нам, что страница полностью отобразилась, а основной поток JavaScript настроен (низкая активность процессора в течение нескольких секунд).

Здесь мы устанавливаем бюджет для CNN «First meaningful paint» на < 5 секунд.

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

Calibre отображает приоритет сетевых запросов, поэтому вы можете быть уверены в сделанных запросах. Выбирайте приоритеты и улучшайте производительность.

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

Ваш чеклист для критических запросов:

  • ✅ Включите колонку Priority в Chrome DevTools.
  • ✅ Определите, какие запросы должны быть сделаны, прежде чем пользователи смогут увидеть полностью отображённую страницу.
  • ✅ Сократите количество требуемых критических запросов, где это возможно.
  • ✅ Используйте для ресурсов, которые, вероятно, будут использоваться на следующей странице сайта.
  • ✅ Используйте <link https://example.com/other/styles.css rel=preload as=style> nopush HTTP-заголовки, чтобы сообщить браузеру, какие ресурсы предварительно загружать до того, как HTML был полностью доставлен.
  • 🚫 Серверный HTTP/2 пуш тернист. Наверное, пока стоит его избегать. (См. этот информативный документ от Тома Бергана, Саймона Пелчата и Майкла Бюттнера, а также «HTTP/2 Push более жесткий, чем я думал» Джейка Арчибальда).
  • ✅ Используйте font-display: swap; с веб-шрифтами, где это возможно.
  • ⏱ Используются ли веб-шрифты? Могут ли они быть удалены? Если нет: назначьте их приоритет и используйте WOFF2!
  • ⏱ Является ли поздняя загрузка скриптов задерживающим фактором для отображения вашего одностраничного приложения в целом?
  • 📹 Посмотрите этот отличный бесплатный скринкаст от Front End Center, демонстрирующий, как загружать веб-сайты с наилучшим возможным опытом фоллбеков.
  • 🔍 Откройте chrome://net-internals/#events и загрузите страницу — это лог сетевых событий.
  • Нет запроса быстрее, чем отсутствие запроса.✌️

Слушайте наш подкаст в iTunes и SoundCloud, читайте нас на Medium, контрибьютьте на GitHub, общайтесь в группе Telegram, следите в Twitter и канале Telegram, рекомендуйте в VK и Facebook.

Эта статья на Medium