Я Максим, веб-разработчик. Браузер загружает ресурсы в определённом порядке, и этот порядок не всегда оптимален. Пока браузер парсит HTML, он ещё не знает, какие шрифты, изображения и скрипты понадобятся — и узнает об этом только после обработки CSS и JavaScript. Но вы можете подсказать ему заранее, что потребуется в ближайшее время, — и он начнёт загрузку или подготовку раньше. Для этого существуют три основных инструмента: preload, prefetch и preconnect. Разбираю каждый подробно: как работает, когда применять, что можно сломать и какой реальный эффект ожидать.
Preload — загрузи прямо сейчас с высоким приоритетом
Директива link rel="preload" говорит браузеру: «Этот ресурс точно нужен на текущей странице, начни загрузку с высоким приоритетом прямо сейчас, не дожидаясь, пока обнаружишь его в CSS или JavaScript». Ресурс загружается параллельно с парсингом HTML, но не блокирует рендеринг (в отличие от обычных тегов script без async/defer).
Самый классический пример — веб-шрифты. Без preload браузер узнаёт о шрифте только после того, как загрузит и распарсит CSS-файл, найдёт в нём правило @font-face и определит, что шрифт действительно используется на странице. К этому моменту может пройти 500–1000 миллисекунд с начала загрузки. С preload шрифт начинает загружаться одновременно с HTML — и к моменту рендеринга текста он уже готов. Результат: устранение мигания текста (FOUT/FOIT) и ускорение LCP.
Когда использовать preload: шрифты в формате WOFF2 (обязательно указывать as="font" и crossorigin), hero-изображение на первом экране (as="image"), критический CSS если он загружается отдельным файлом, JavaScript-файл, который нужен для рендеринга первого экрана (as="script").
Критически важное правило: не злоупотребляйте preload. Если вы пометите двадцать ресурсов как preload — браузер потеряет приоритеты, все ресурсы будут конкурировать за канал, и общее время загрузки может даже увеличиться. Оптимальное количество — два-четыре самых критичных ресурса. Я обычно ставлю preload на основной шрифт и hero-изображение — этого достаточно для ощутимого эффекта.
Ещё один нюанс, который ловит многих разработчиков: если вы объявили preload для ресурса, но не использовали его на странице в течение нескольких секунд после загрузки, браузер выведет предупреждение в консоли: «The resource was preloaded using link preload but not used within a few seconds from the window's load event». Это не ошибка, но сигнал о том, что вы тратите ресурсы впустую. Preload — только для того, что точно нужно на текущей странице.
Prefetch — подготовь для следующей страницы
Директива link rel="prefetch" работает иначе. Она говорит браузеру: «Этот ресурс может понадобиться на следующей странице, загрузи его в фоне, когда будет свободная пропускная способность, и положи в кэш». Браузер выполняет prefetch с самым низким приоритетом — загрузка текущей страницы никак не пострадает.
Когда использовать prefetch: вы знаете или можете предположить, куда пользователь перейдёт дальше. На странице каталога — prefetch для страницы первого товара (статистически наиболее вероятный переход). На лендинге с одним CTA — prefetch для страницы оформления заказа. На первом шаге мастера (wizard) — prefetch для второго шага.
На практике prefetch работает отлично для предсказуемых сценариев навигации. На одном из моих проектов — многостраничная форма заявки — я добавил prefetch каждого следующего шага, и визуально переходы стали мгновенными. Пользователь нажимал «Далее» — и следующий экран появлялся без задержки, потому что все ресурсы уже были в кэше.
Важная деталь: prefetch загружает ресурс целиком, расходуя трафик пользователя. На мобильных с лимитированным трафиком это нужно учитывать. Я не использую prefetch для тяжёлых ресурсов (видео, большие изображения) — только для HTML-страниц, небольших скриптов и стилей.
Существует также более агрессивный вариант — prerender (ранее speculationrules API), который не просто загружает ресурс, а полностью рендерит страницу в фоновом режиме. При переходе пользователь видит уже готовую отрендеренную страницу мгновенно. Это мощный инструмент, но применять его нужно осторожно — он потребляет значительные ресурсы CPU и памяти.
Preconnect — установи соединение заранее
Директива link rel="preconnect" решает другую задачу. Она не загружает конкретный ресурс, а заранее устанавливает TCP-соединение, выполняет TLS-рукопожатие и DNS-резолвинг к стороннему домену — до того, как первый ресурс с этого домена потребуется.
Зачем это нужно? Каждое соединение с новым доменом включает три этапа: DNS-резолвинг (50–200 мс), TCP-рукопожатие (50–100 мс) и TLS-рукопожатие для HTTPS (100–200 мс). В сумме — от 200 до 500 миллисекунд задержки до начала загрузки первого байта. Preconnect выполняет всё это заранее, в фоне, — и когда ресурс реально понадобится, соединение уже готово.
Когда использовать: перед загрузкой ресурсов с внешних доменов. Google Fonts (fonts.googleapis.com и fonts.gstatic.com — два разных домена, оба нужно preconnect). CDN с изображениями. Яндекс Метрика (mc.yandex.ru). Виджет чата. Карты. Любой сторонний домен, к которому ваш сайт обращается в процессе загрузки.
Ограничения: не ставьте preconnect на больше чем четыре-пять доменов. Каждое установленное соединение потребляет ресурсы браузера и сервера. Если соединение установлено, но не используется в течение десяти секунд, — оно закрывается, и ресурсы потрачены впустую.
dns-prefetch — лёгкая альтернатива preconnect
Если preconnect устанавливает полное соединение (DNS + TCP + TLS), то dns-prefetch выполняет только DNS-резолвинг — определяет IP-адрес домена заранее. Это легче, быстрее и потребляет минимум ресурсов.
Я использую dns-prefetch для доменов, к которым сайт обращается не сразу — например, домен виджета чата, который загружается через пять секунд после загрузки страницы, или домен карт, которые находятся в нижней части страницы. Preconnect — для двух-трёх самых важных сторонних доменов, от которых зависит рендеринг первого экрана.
Практический набор для типичного коммерческого сайта
Для среднего коммерческого сайта на Next.js или WordPress мой типичный набор resource hints выглядит так.
Preconnect к CDN с изображениями (если используете внешний CDN) и к домену основной аналитики. Preload для основного шрифта в формате WOFF2 и для hero-изображения на главной странице. Dns-prefetch для домена виджета чата, Яндекс Карт, социальных сетей (VK API для виджетов).
Суммарный эффект этого набора: ускорение LCP на 200–500 миллисекунд, устранение мигания шрифтов, субъективно более быстрая загрузка сторонних виджетов. И всё это — бесплатно, без изменения кода приложения, только за счёт нескольких тегов link в секции head.
На одном проекте — лендинг для строительной компании — добавление preconnect к CDN с фотографиями и preload hero-изображения улучшило LCP с 3.8 секунды до 2.1 секунды. Страница визуально загружалась почти вдвое быстрее, а единственное изменение — три строки HTML в head.
Типичные ошибки при работе с resource hints
Первая ошибка — preload без использования. Вы объявили preload для ресурса, но забыли его подключить (например, поменяли путь к шрифту в CSS, а preload остался со старым путём). Ресурс загружается, тратит трафик и пропускную способность, но никогда не используется.
Вторая — слишком много preconnect. Каждое полное соединение потребляет ресурсы. Больше пяти preconnect — перебор, который может навредить производительности вместо того, чтобы помочь.
Третья — неуказание атрибута crossorigin для шрифтов в preload. Шрифты всегда загружаются в CORS-режиме, и если в preload не указать crossorigin — браузер загрузит шрифт дважды: один раз по preload (без CORS) и второй раз при обнаружении в CSS (с CORS). Это не ускоряет, а замедляет.
Четвёртая — использование prefetch на мобильных для тяжёлых ресурсов. Загрузка десятимегабайтного видео в фоне ради предполагаемого перехода — плохая идея на мобильном интернете с ограниченным трафиком.
Resource hints — один из самых простых и эффективных способов ускорить сайт. Три-пять тегов в head, пятнадцать минут работы — и вы получаете измеримое улучшение Core Web Vitals. Добавьте, замерьте разницу в Lighthouse и PageSpeed Insights — результат вас приятно удивит.