Preload, prefetch и другие теги

Есть много способов повышения веб-производительности. Один из них — предзагрузка контента, который понадобится позже. Префтечинг CSS, предварительный рендеринг полной страницы или резолвинг доменного имени. Делаем всё заранее, а потом мгновенно отображаем результат! Звучит круто.

Ещё круче, что это очень просто реализовано. Пять тегов <link rel> дают браузеру команду на предварительные действия:

<link rel="prefetch" href="/style.css" as="style" />
<link rel="preload" href="/style.css" as="style" />

<link rel="preconnect" href="https://example.com" />
<link rel="dns-prefetch" href="https://example.com" />

<link rel="prerender" href="https://example.com/about.html" />


Вкратце расскажем, что они делают и когда их использовать.

Перейти к: preload · prefetch · preconnect · dns-prefetch · prerender

preload

<link rel= "preload"> говорит браузеру как можно скорее загрузить и кэшировать ресурс (например, скрипт или таблицу стилей). Это полезно, когда ресурс понадобится через несколько секунд после загрузки страницы — и вы хотите ускорить процесс.

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

Синтаксис

<link rel="preload" href="/style.css" as="style" />

href указывает на ресурс, который вы хотите скачать.

as может быть чем угодно, что можно скачать в браузере:

  • style для таблиц стилей,
  • script для скриптов,
  • font для шрифтов,
  • fetch для ресурсов, загруженных с помощью fetch() или XMLHttpRequest,
  • полный список см. на MDN.

Важно указать атрибут as – это помогает браузеру правильно расставлять приоритеты и планировать загрузку.

Когда использовать

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

  • Нестандартные шрифты из внешнего файла:
    <!-- index.html -->
    <link rel="stylesheet" href="index.css" />
    /* index.css */
    @font-face {
      src: url('comic-sans.woff2') format('woff2');
    }

    По умолчанию comic-sans.woff2 начнёт загружаться только после загрузки и разбора index.css. Чтобы не ждать так долго, можно загрузить шрифт раньше с помощью <link rel= "preload">:

    <link rel="preload" href="comic-sans.woff2" as="font" />
  • Если вы разделяете свои стили согласно подходу Critical CSS на две части, критическую (для немедленного рендеринга) и некритическую:
    <style>
    /* Inlined critical styles */
    </style>
    
    <script>
    /* Custom JS that starts downloading non-critical styles */
    loadCSS('/app/non-critical.css');
    </script>

    При таком подходе некритические стили начнут загружаться только при запуске JavaScript, что может произойти через несколько секунд после рендеринга. Вместо ожидания JS используйте <link rel= "preload">, чтобы начать загрузку раньше:

    <style>
    /* Inlined critical styles */
    </style>
    
    <link rel="preload" href="/app/non-critical.css" as="style" />
    
    <script>
    /* Custom JS that starts downloading non-critical styles */
    loadCSS('/app/non-critical.css');
    </script>

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

Не путайте с префетчингом. Не используйте <link rel= "preload">, если вам не нужен ресурс сразу после загрузки страницы. Если он понадобится позже, например, для следующей страницы, то используйте <link rel= "prefetch">.

Подробности

Это обязательный тег для исполнения браузером (если он его поддерживает), в отличие от всех других тегов <link>, связанных с предварительной загрузкой. Браузер обязан загрузить ресурс, указанный в <link rel="preload">. В других случаях он может проигнорировать предварительную загрузку, например, если работает на медленном соединении.

Приоритеты. Разным ресурсам (стили, скрипты, шрифты и т. д.), браузеры обычно назначают разные приоритеты, чтобы в первую очередь загружать самые важные ресурсы. В данном случае браузер определяет приоритет по атрибуту as. Для браузера Chrome можете посмотреть полную таблицу приоритетов.

Preload, prefetch и другие теги

prefetch

<link rel= "prefetch"> просит браузер загрузить и кэшировать ресурс (например, скрипт или таблицу стилей) в фоновом режиме. Загрузка происходит с низким приоритетом, поэтому не мешает более важным ресурсам. Это полезно, если ресурс понадобится на следующей странице, а вы хотите заранее его кэшировать.

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

Синтаксис

<link rel="prefetch" href="/style.css" as="style" />

href указывает на ресурс, который вы хотите скачать.

as может быть чем угодно, что можно скачать в браузере:

  • style для таблиц стилей,
  • script для скриптов,
  • font для шрифтов,
  • fetch для ресурсов, загруженных с помощью fetch() или XMLHttpRequest,
  • полный список см. на MDN.

Важно указать атрибут as — это помогает браузеру правильно расставлять приоритеты и планировать загрузку.

Когда использовать

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

  • У вас интернет-магазин, и 40% пользователей уходят с главной страницы на страницу товара. Используйте <link rel= "prefetch">, загружая файлы CSS и JS для рендеринга страниц с продуктом.
  • У вас одностраничное приложение, а разные страницы загружают разные пакеты. Когда пользователь посещает какую-то страницу, можно предварительно загрузить пакеты для всех страниц, на которые она ссылается.

Вероятно, этот тег можно безопасно использовать в любом объёме. Браузеры обычно планируют prefetch с наименьшим приоритетом, так что он никому не мешает. Только имейте в виду, что расходуется трафик пользователя, который может стоить денег.

Не для срочных запросов. Не используйте <link rel= "prefetch">, когда ресурс понадобится через несколько секунд. В этом случае применяйте <link rel= "preload">.

Подробности

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

Приоритет в Chrome. В Chrome <link rel= "prefetch"> обычно выполняется с минимальным приоритетом (см. полную таблицу приоритетов), то есть после загрузки всего остального.

preconnect

<link rel= "preconnect"> просит браузер заранее подключиться к домену, когда вы хотите ускорить установку соединения в будущем.

Браузер должен установить соединение, если извлекает какие-то ресурсы с нового стороннего домена. Например, если загружает шрифты Google Fonts, React из CDN или запрашивает ответ JSON с сервера API.

Установка нового соединения обычно занимает несколько сотен миллисекунд. Она производится один раз, но всё равно отнимает время. Если вы заранее установили соединение, то сэкономите время и быстрее загрузите ресурсы с этого домена.

Синтаксис

<link rel= "preconnect" href="https://api.my-app.com" />

href указывает на доменное имя, для которого нужно определить IP-адрес. Можно указывать с префиксом (https://domain.com) или без него (//domain.com).

Когда использовать

Используйте для доменов, которые скоро понадобятся для загрузки оттуда важного стиля, скрипта или изображения, но вы пока не знаете URL ресурса. Например:

  • Ваше приложение размещается на my-app.com и делает AJAX-запросы к api.my-app.com: вы не знаете заранее конкретные запросы, потому что они делатся динамически из JS. Здесь вполне уместно использование тега для предварительного подключения к домену.
  • Ваше приложение размещается на my-app.com и использует шрифты Google Fonts. Они загружаются в два этапа: сначала загружается файл CSS с домена fonts.googleapis.com, затем этот файл запрашивает шрифты с fonts.gstatic.com. Вы не можете знать, какие конкретные файлы шрифтов из fonts.gstatic.com вам понадобятся, пока не загрузите файл CSS, поэтому заранее мы можем только установить предварительное соединение.

Используйте этот тег, чтобы немного ускорить какой-то сторонний скрипт или стиль за счёт предварительной установки соединения.

Не злоупотребляйте. Установка и поддержание соединения — дорогостоящая операция как для клиента, так и для сервера. Используйте этот тег максимум для 4-6 доменов.

Подробности

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

Что включает в себя процесс подключения. Для подключения к каждому сайту браузер должен выполнить следующие действия:

  • Резолвинг DNS. Найти IP-адрес сервера (216.58.215.78) для указанного доменного имени (google.com).
  • Рукопожатие TCP. Обмен пакетами (клиент → сервер → клиент), чтобы инициировать TCP-соединение с сервером.
  • Рукопожатие TLS (только для сайтов HTTPS). Два раунда обмена пакетами (клиент → сервер → клиент → сервер → клиент), чтобы инициировать безопасный сеанс TLS.

Примечание: HTTP/3 улучшит и ускорит механизм рукопожатия, но он ещё далеко.

dns-prefetch

<link rel= "dns-prefetch"> просит браузер заранее выполнить резолвинг DNS для домена, если вы скоро будете подключаться к нему и хотите ускорить начальное соединение.

Браузер должен определить IP-адрес домена, если будет извлекать какие-то ресурсы с нового стороннего домена. Например, загружать шрифты Google Fonts, React из CDN или запрашивать ответ JSON с сервера API.

Для каждого нового домена разрешение записи DNS обычно занимает около 20−120 мс. Это влияет только на загрузку первого ресурса с данного домена, но всё равно представляет задержку. Если осуществить разрешение DNS заранее, то мы сэкономим время и загрузим ресурс быстрее.

Синтаксис

<link rel= "dns-prefetch" href="https://api.my-app.com" />

href указывает на доменное имя, для которого нужно установить IP-адрес. Можно указывать с префиксом (https://domain.com) или без него (//domain.com).

Когда использовать

Используйте для доменов, которые скоро понадобятся для загрузки оттуда ресурсов, о которых браузер не знает заранее. Например:

  • Ваше приложение размещается на my-app.com и делает AJAX-запросы к api.my-app.com: вы не знаете заранее конкретные запросы, потому что они делатся динамически из JS. Здесь вполне уместно использование тега для предварительного подключения к домену.
  • Ваше приложение размещается на my-app.com, и использует шрифты Google Fonts. Они загружаются в два этапа: сначала загружается файл CSS с домена fonts.googleapis.com, затем этот файл запрашивает шрифты с fonts.gstatic.com. Вы не можете знать, какие конкретные файлы шрифтов из fonts.gstatic.com вам понадобится, пока не загрузите файл CSS, поэтому заранее мы можем только установить предварительное соединение.

Используйте этот тег, чтобы немного ускорить какой-то сторонний скрипт или стиль за счёт предварительной установки соединения.

Обратите внимание схожие характеристики на <link rel= "dns-prefetch"/> и <link rel= "preconnect">. Использовать их вместе для одного домена обычно не имеет смысла: <link rel= "preconnect"> уже включает в себя <link rel= "dns-prefetch"/> и многое другое. Это можно оправдать в двух случаях:

  • Вы хотите поддерживать старые браузеры. <link rel= "dns-prefetch" /> поддерживается начиная с IE10 и Safari 5. <link rel= "preconnect"> некоторое время поддерживался в Chrome и Firefox, но был добавлен в Safari только в 11.1 и по-прежнему не поддерживается в IE/Edge. Если нужно поддерживать эти браузеры, используйте <link rel= "dns-prefetch" /> в качестве запасного варианта для <link rel= "preconnect">.
  • Вы хотите ускорить подключение более чем к 4−6 доменам. Тег <link rel= "preconnect"> не рекомендуется использовать более чем с 4−6 доменами, так как установка и поддержание соединения — дорогостоящая операция. <link rel= "dns-prefetch" /> потребляет меньше ресурсов, поэтому в случае необходимости используйте его.

Подробности

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

Что такое DNS. Каждому серверу в интернете соответствует уникальный IP-адрес, который выглядит как 216.58.215.78. В адресной строке браузера обычно вводится название сайта (например, google.com), а серверы DNS (Domain Name System) сопоставляют его с IP-адресом сервера (216.58.215.78).

Чтобы определить IP-адрес, браузер должен выполнить запрос к DNS-серверу. Он занимает 20−120 мс при подключении к новому стороннему домену.

DNS кэшируется, хотя и не очень надёжно. Некоторые ОС и браузеры кэшируют DNS-запросы: это сэкономит время при повторных запросах, но на кэширование нельзя полагаться. В Linux оно обычно вообще не работает. У Chrome есть кэш DNS, но он живёт только минуту. Windows кэширует DNS-ответы в течение пяти дней.

prerender

<link rel= "prerender"> просит браузер загрузить URL-адрес и отобразить его на невидимой вкладке. Когда пользователь нажимает на ссылку, страница должна отобразиться немедленно. Это полезно, если вы уверены, что пользователь посетит определённую страницу, и хотите ускорить её отображение.

Несмотря на исключительную эффективность этого тега (или из-за неё), в 2019 году <link rel= "prerender"> плохо поддерживается основными браузерах. Подробнее см. ниже.

Синтаксис

<link rel="prerender" href="https://my-app.com/pricing" />

href указывает на URL, для который вы хотите запустить рендеринг в фоновом режиме.

Когда использовать

Когда вы действительно уверены, что пользователь перейдёт на определённую страницу. Если у вас «туннель», по которому 70% посетителей страницы A переходят на страницу Б, то <link rel= "prerender"> на странице А поможет очень быстро отобразить страницу Б.

Не злоупотребляйте. Предварительный рендеринг чрезвычайно дорого обходится с точки зрения трафика и памяти. Не используйте <link rel= "prerender"> более чем для одной страницы.

Подробности

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

Ради экономии памяти Chrome не выполняет полный рендеринг, а только предзагрузку NoState. Это означает, что Chrome загружает страницу и все её ресурсы, но не делает рендеринг и не выполняет JavaScript.

Firefox и Safari вообще не поддерживают этот тег. Это не нарушает спецификацию, так как браузеры не обязаны выполнять данную инструкцию; но всё равно печально. Баг реализации в Firefox был открыт в течение семи лет. Есть сообщения, что Safari тоже не поддерживает этот тег.

Резюме

Используйте:

  • <link rel= "preload"> — когда вам понадобится ресурс через несколько секунд
  • <link rel= "prefetch"> — когда понадобится ресурс на следующей странице
  • <link rel= "preconnect"> — когда вы знаете, что вам скоро понадобится ресурс, но вы ещё не знаете его полный URL
  • <link rel= "dns-prefetch"> — аналогично, когда вы знаете, что вам скоро понадобится ресурс, но вы ещё не знаете его полный URL (для старых браузеров)
  • <link rel= "prerender"> — когда вы уверены, что пользователи перейдут на определённую страницу, и хотите ускорить её отображение

Источник: habr.com