Хабрахабр

[Перевод] Ускорение сайтов с помощью «ранних подсказок»

Сайты по-прежнему загружаются слишком медленно. В самый критический момент процесса загрузки канал зачастую практически полностью простаивает. Новая технология, предложенная инженером Кадзухо Оку из Fastly, поможет лучше использовать эту критическую первую пару секунд.

Никто не любит сидеть и глядеть на пустой экран, пока загружается какой-то необычный шрифт. Вы когда-нибудь загружали сайт на телефоне — и смотрели в течение 10 секунд на страницу без текста? Предзагрузка Link rel=preload должна была частично решить проблему. Поэтому есть смысл перенести загрузку таких важных вещей на максимально раннее время. Первым делом браузер парсит HTTP-заголовки, так что это идеальное место, чтобы указать на предварительную загрузку ресурса, который точно понадобится позже.

Давайте посмотрим, что произойдёт, если не использовать предзагрузку. Браузер может начать загрузку ресурсов только после того, как обнаружил, что он в них нуждается. Это быстрее всего происходит для ресурсов, которые находятся в HTML во время первоначального разбора документа (например, <script>, <link rel=stylesheet> и <img>).

Медленнее скачиваются ресурсы, которые обнаруживаются после построения дерева рендеринга (это место, где страница тормозит из-за загрузки шрифта, ведь чтобы понять это, сначала нужно загрузить таблицу стилей, разобрать её, построить объектную модель CSS, а затем дерево рендеринга).

Если собрать всё вместе, мы получаем неоптимизированный и довольно бессмысленный водопад. Ещё медленнее загружаются ресурсы, которые добавлены в документ с помощью загрузчиков JavaScript, которые запускаются событиями вроде DOMContentLoaded. Значительную часть времени канал простаивает, а ресурсы загружаются или раньше, чем необходимо, или слишком поздно:

В последние несколько лет ситуация улучшилась благодаря Link rel=preload. Например:

Link: </resources/fonts/myfont.woff>; rel=preload; as=font; crossorigin
Link: </resources/css/something.css>; rel=preload; as=style
Link: </resources/js/main.js>; rel=preload; as=script

Благодаря этим директивам браузер может начать загрузку ресурсов сразу после получения заголовков и перед началом анализа тела HTML:

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

Ведь браузер ничего не делает между моментом, когда заканчивает отправку запроса, и когда получает первые байты ответа (большой зелёный фрагмент на начальном запросе выше). Однако мы можем добиться большего.

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

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

В конце концов, страницы ошибок обычно используют тот же фирменный стиль и дизайн, что и обычные страницы. Но интересно, что ещё до генерации ответа вы уже знаете некоторые стили и шрифты, которые необходимо загрузить для отображения страницы. Именно для этого задуман стандарт «ранних подсказок» Early Hints, указанный в RFC8297 от Рабочей группы HTTP за авторством моего коллеги Кадзухо Оку из Fastly. Было бы здорово отправить эти заголовки Link: rel=preload ещё перед работой сервера. Оцените магию нескольких строк состояния в одном ответе:

HTTP/1.1 103 Early Hints
Link: <some-font-face.woff2>; rel="preload"; as="font"; crossorigin
Link: <main-styles.css>; rel="preload"; as="style" HTTP/1.1 404 Not Found
Date: Fri, 26 May 2017 10:02:11 GMT
Content-Length: 1234
Content-Type: text/html; charset=utf-8
Link: <some-font-face.woff2>; rel="preload"; as="font"; crossorigin
Link: <main-styles.css>; rel="preload"; as="style"

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

Поэтому до сих пор неясно, когда данные заголовки можно внедрить в эксплуатацию. Конечно, это потребует определённых изменений в работе браузеров, серверов и CDN, и разработчики некоторых браузеров высказали оговорки относительно трудностей реализации. Вы можете отслеживать прогресс в публичных трекерах для Chrome и Firefox.

Мы ещё не решили, как выставить интерфейс через VCL, поэтому сообщите, если у вас есть пожелания на этот счёт! Мы рассчитываем, что в конечном итоге вы сможете выдавать заголовки Early Hints прямо из Fastly, по-прежнему отправляя запросы стандартным образом.

С HTTP/2 идёт новая технология под названием Server Push, которая вроде бы решает ту же проблему, что и Link rel=preload в ответе Early Hints. Хотя она действительно работает (и вы даже можете быстро генерировать кастомные пуши с edge-серверов в Fastly), но есть существенная разница по нескольким пунктам:

  • Сервер не знает о наличии ресурса у клиента, поэтому часто пушит его без необходимости. Из-за буферизации сети и задержки клиент обычно не может отменить отправку перед получением всего содержимого. (Хотя есть возможное решение этой проблемы, в виде предлагаемого заголовка Cache Digest, над которым Кадзухо работает вместе с Йоавом Вайсом из Akamai).
  • Запушенные ресурсы привязаны к соединению, поэтому легко запушить ресурс, который клиент не использует, так как он пытается получить его через другое соединение. Клиентам может потребоваться использовать другое подключение, поскольку ресурс находится в другом источнике с другим сертификатом TLS или поскольку он извлекается в другом режиме учётных данных.
  • H2 Push не очень последовательно реализован в разных браузерах. Поэтому трудно предсказать, будет он работать или нет в вашем конкретном случае.

Так или иначе, Early Hints и Server Push предлагают разные компромиссы. Подсказки Early Hints обеспечивают более эффективное использование сети в обмен на дополнительный обмен пакетами. Если вы предполагаете малую задержку в сети и длительное время на обдумывание сервера, то Early Hints — правильное решение.

Давайте будем оптимистами и представим, что люди скоро поселятся на Марсе. Однако, это не всегда так. Здесь легко побеждает Server Push. Они будут просматривать веб-страницы с задержкой 20-45 минут на каждый обмен пакетами, поэтому дополнительный обмен исключительно болезненен, а серверное время несущественно по сравнению с ним. Но если мы когда-либо будем просматривать веб-страницы с Марса, то скорее скачаем какой-то пакет с данными, нечто вроде предлагаемых сейчас веб-пакетов и подписанных обменов.

Хотя Early Hints предполагается использовать в первую очередь в браузере, но есть интересная потенциальная выгода и для CDN. Когда Fastly получает много запросов на один и тот же ресурс, мы обычно отправляем источнику только один из них, а остальные помещаем в очередь ожидания. Этот процесс известен как свёртывание запроса (request collapsing). Если ответ от источника включает в себя Cache-Control: private, то следует убрать из очереди все запросы и отправить источнику их по отдельности, потому что мы не можем использовать один ответ для удовлетворения нескольких запросов.

Мы не можем принять решение, пока не получен ответ на первый запрос, но в случае поддержки Early Hints, если сервер выдал ответ Early Hints с заголовком Cache-Control, то мы намного раньше узнаем, что очередь нельзя свернуть в один запрос, а вместо этого немедленно направим источнику все запросы из очереди.

Ранние подсказки — отличный способ получить доступ к некоторым из самых ценных объектов в очереди (водопаде): когда сеть простаивает, то пользователь ждёт, в пути только один запрос, и на экране ничего нет. Но как только загружен HTML и страница проанализирована, то резко возрастает количество ресурсов, которые нуждаются в загрузке. Теперь важно не загружать ресурсы как можно быстрее, а загружать их в правильном порядке. Браузеры используют поразительно сложный массив эвристик, чтобы самостоятельно определить приоритет загрузки, но если вы хотите переопределить их, то в будущем это можно будет сделать с помощью подсказок приоритета (Priority Hints):

<script src="main.js" async importance="high"></script>
<script src="non-critical-1.js" async importance="low"></script>

С помощью этого нового атрибута важности разработчики могут управлять порядком загрузки ресурсов в случае конкуренции за сеть. Возможно, ресурсы низкого приоритета можно отложить до тех пор, пока процессор и сеть не освободятся, или в зависимости от типа устройства.
Ни ранние подсказки, ни подсказки приоритета пока не стали стандартом. Недавно H2O, сервер HTTP/2, используемый и поддерживаемый Fastly, начал применять Early Hints (см. PR 1727 и 1767), и есть намерение реализовать Priority Hints в Chrome, также как активное отслеживание ответов 1xx. В то же время нет никакого вреда в том, чтобы уже сейчас начать отправлять Early Hints — и если вы хотите опередить тренд, то вперёд!

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть