Есть много способов повышения веб-производительности. Один из них — предзагрузка контента, который понадобится позже. Префтечинг CSS, предварительный рендеринг полной страницы или резолвинг доменного имени. Делаем всё заранее, а потом мгновенно отображаем результат! Звучит круто.
Ещё круче, что это очень просто реализовано. Пять тегов <link rel> дают браузеру команду на предварительные действия:
<link rel= "preload"> говорит браузеру как можно скорее загрузить и кэшировать ресурс (например, скрипт или таблицу стилей). Это полезно, когда ресурс понадобится через несколько секунд после загрузки страницы — и вы хотите ускорить процесс.
Браузер ничего не делает с ресурсом после загрузки. Скрипты не выполняются, таблицы стилей не применяются. Ресурс просто кэшируется и немедленно предоставляется по запросу.
По умолчанию comic-sans.woff2 начнёт загружаться только после загрузки и разбора index.css. Чтобы не ждать так долго, можно загрузить шрифт раньше с помощью <link rel= "preload">:
При таком подходе некритические стили начнут загружаться только при запуске JavaScript, что может произойти через несколько секунд после рендеринга. Вместо ожидания JS используйте <link rel= "preload">, чтобы начать загрузку раньше:
Не злоупотребляйте предзагрузкой. Если загружать всё подряд, сайт не ускорится волшебным образом, скорее наоборот, это помешает браузеру грамотно планировать работу.
Не путайте с префетчингом. Не используйте <link rel= "preload">, если вам не нужен ресурс сразу после загрузки страницы. Если он понадобится позже, например, для следующей страницы, то используйте <link rel= "prefetch">.
Подробности
Это обязательный тег для исполнения браузером (если он его поддерживает), в отличие от всех других тегов <link>, связанных с предварительной загрузкой. Браузер обязан загрузить ресурс, указанный в <link rel="preload">. В других случаях он может проигнорировать предварительную загрузку, например, если работает на медленном соединении.
Приоритеты. Разным ресурсам (стили, скрипты, шрифты и т. д.), браузеры обычно назначают разные приоритеты, чтобы в первую очередь загружать самые важные ресурсы. В данном случае браузер определяет приоритет по атрибуту as. Для браузера Chrome можете посмотреть полную таблицу приоритетов.
prefetch
<link rel= "prefetch"> просит браузер загрузить и кэшировать ресурс (например, скрипт или таблицу стилей) в фоновом режиме. Загрузка происходит с низким приоритетом, поэтому не мешает более важным ресурсам. Это полезно, если ресурс понадобится на следующей странице, а вы хотите заранее его кэшировать.
Здесь тоже браузер ничего не делает с ресурсом после загрузки. Скрипты не выполняются, таблицы стилей не применяются. Ресурс просто кэшируется и немедленно предоставляется по запросу.
Важно указать атрибут 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.
Установка нового соединения обычно занимает несколько сотен миллисекунд. Она производится один раз, но всё равно отнимает время. Если вы заранее установили соединение, то сэкономите время и быстрее загрузите ресурсы с этого домена.
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 заранее, то мы сэкономим время и загрузим ресурс быстрее.
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"> плохо поддерживается основными браузерах. Подробнее см. ниже.
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"> — когда вы уверены, что пользователи перейдут на определённую страницу, и хотите ускорить её отображение