Есть много способов повышения веб-производительности. Один из них — предзагрузка контента, который понадобится позже. Префетчинг 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 можете посмотреть полную таблицу приоритетов.
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">
— когда вы уверены, что пользователи перейдут на определённую страницу, и хотите ускорить её отображение
Автор: m1rko