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

Andrey Melikhov
Aug 9, 2017 · 8 min read

Перевод статьи 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 Preview, столбец приоритета (новый!) можно включить точно так же.

Включите столбец «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, если они появляются в разметке перед изображением.

Шрифты — это немного странное существо: они являются очень важным ресурсом (кто из вас любит игру «Я вижу это!», «Теперь не вижу», «Ура, новый шрифт!»?). Поэтому в том, что шрифты загружаются с приоритетом 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. Если все остальное провалится, пользователь все равно может прочитать страницу.

Эти ресурсы (обратите внимание на отсутствие 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.

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

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

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

Я провёл два теста на 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) сообщает нам, когда браузер переходит от «ничего к чему-то».
Здесь мы устанавливаем бюджет для CNN «First meaningful paint» на < 5 секунд.

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

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

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

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

  • ✅ Включите колонку Priority в Chrome DevTools.

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

Эта статья на GitHub

devSchacht

Подкаст. Переводы. Веб-разработка.

Andrey Melikhov

Written by

Web-developer in big IT company Перевожу всё, до чего дотянусь. Иногда (но редко) пишу сам.

devSchacht

Подкаст. Переводы. Веб-разработка.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade