Web Performance

Preload, prefetch и preconnect: когда каждый действительно помогает

Resource hints полезны, когда они соответствуют реальным узким местам браузера. При слепом использовании они добавляют шум в приоритеты и иногда замедляют страницы.

The Wux Webtools Team The Wux Webtools Team 2 минуты чтения С поддержкой ИИ, проверено человеком
A simplified browser loading waterfall showing early resource hints for a web page.
Содержание
  1. Resource hints — не магия
  2. Что браузер уже делает хорошо
  3. Preload: для ресурсов текущей страницы, обнаруживаемых слишком поздно
  4. Preload и LCP images
  5. Prefetch: для следующей страницы, а не для этой
  6. Preconnect: для дорогих соединений с важными origins
  7. DNS-prefetch: более легкий родственник
  8. Как решить: практический workflow
  9. 1. Найдите узкое место
  10. 2. Добавляйте по одной подсказке
  11. 3. Проверяйте побочные эффекты приоритетов
  12. 4. Проверяйте headers и caching
  13. Распространенные ошибки
  14. Preload слишком многого
  15. Использование prefetch для обязательных ресурсов
  16. Preconnect к каждой третьей стороне
  17. Игнорирование мобильных условий
  18. Простая таблица решений
  19. Спокойное правило

Resource hints — не магия

preload, prefetch и preconnect часто воспринимают как чек-лист производительности. Добавить несколько тегов в <head>, снова запустить Lighthouse и почувствовать себя спокойнее. Но они работают не так.

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

Коротко:

  • Используйте preload для ресурсов, нужных текущей странице, но обнаруживаемых слишком поздно.
  • Используйте prefetch для вероятных ресурсов будущей навигации, а не для важных ресурсов текущей страницы.
  • Используйте preconnect для важных сторонних origins, где установка соединения действительно создает задержку.

Практический вопрос не в том, “какая подсказка самая быстрая?”. А в том, “чего ждет браузер и может ли эта подсказка убрать ожидание?”.

Что браузер уже делает хорошо

Современные браузеры — не пассивные загрузчики файлов. Они парсят HTML, заранее сканируют ресурсы, назначают приоритеты, переиспользуют соединения, откладывают невидимую работу и адаптируются к сетевым условиям.

Поэтому resource hints должны быть избирательными. Если stylesheet, script, image или font уже обнаруживается рано и получает правильный приоритет, добавление подсказки может ничего не изменить. Хуже того, она может начать конкурировать с ресурсами, которые важнее.

Прежде чем добавлять подсказки, посмотрите waterfall trace в DevTools или лабораторный отчет. Если вы используете Lighthouse, начните с diagnostics, а не с балла; у нас есть отдельное руководство о том, как читать отчет Lighthouse без паники — но учтите, что правильный URL чувствителен к регистру, поэтому при необходимости используйте связанную статью из навигации вашего сайта.

Настоящие доказательства обычно видны в трех местах:

  1. Критический ресурс стартует поздно, потому что браузер поздно его обнаруживает.
  2. Соединение с важным origin занимает заметное время до первого запроса.
  3. Ресурс следующей страницы хорошо предсказуем, и его дешево получить в простое.

Если ничего из этого не верно, подсказка, вероятно, просто украшение.

Preload: для ресурсов текущей страницы, обнаруживаемых слишком поздно

preload говорит браузеру: “Загрузи этот ресурс сейчас, потому что он понадобится текущей странице”.

Типичный пример — web font, на который ссылаются внутри CSS. Браузер должен загрузить HTML, обнаружить CSS, загрузить CSS, распарсить его, обнаружить font и только затем запросить font. Если этот font важен для текста above-the-fold, обнаружение может оказаться достаточно поздним, чтобы вызвать layout shifts или задержку отрисовки текста.

Preload может сдвинуть этот запрос раньше:

<link rel='preload' href='/fonts/inter-var.woff2' as='font' type='font/woff2' crossorigin>

Атрибут as важен. Он сообщает браузеру, что это за тип ресурса, а это влияет на приоритет, кэширование, content security policy и заголовки запроса. Fonts также обычно требуют crossorigin, даже если отдаются с того же сайта, потому что загрузка fonts использует режим CORS.

Хорошие кандидаты для preload:

  • Основной web font, используемый для видимого текста.
  • Hero image, который является элементом Largest Contentful Paint и не обнаруживается рано.
  • Критический CSS-файл, загружаемый косвенно.
  • Module или script, который нужен очень рано, но скрыт за другим script.

Плохие кандидаты для preload:

  • Каждый font weight в design system.
  • Images below the fold.
  • Scripts, которые не нужны для начального рендеринга.
  • Ресурсы, которые браузер уже обнаруживает в первом фрагменте HTML.

Preload мощен, потому что влияет на приоритеты текущей страницы. По этой же причине им легко злоупотребить. Если вы preload пять крупных assets, вы уже не помогаете браузеру. Вы с ним спорите.

Fonts — классический случай. Preload одного основного файла font может помочь. Preload шести weights и italics обычно ухудшает ситуацию. Если fonts — ваше узкое место, сначала исправьте набор fonts; наше руководство о том, почему web fonts по-прежнему остаются самой простой победой в производительности на большинстве сайтов, подробнее описывает такую очистку.

Preload и LCP images

Preload LCP image может быть полезен, когда image не виден в начальном HTML. Частые причины — CSS background images, client-rendered components или responsive image logic, появляющаяся поздно.

Но если ваш hero image уже находится в HTML как <img> с разумными srcset, sizes, dimensions и без lazy loading, браузер, скорее всего, быстро его найдет. В этом случае fetchpriority='high' может быть уместнее, чем preload, в зависимости от страницы.

Хороший тест: если запрос image стартует поздно в waterfall и становится LCP element, рассмотрите preload. Если он стартует рано, но скачивается медленно, проблема в размере, формате, поведении CDN или задержке сервера — а не в обнаружении. О выборе форматов изображений см. когда AVIF лучше WebP и когда нет.

Prefetch: для следующей страницы, а не для этой

prefetch говорит браузеру: “Этот ресурс может понадобиться скоро, но прямо сейчас он не требуется”.

Это различие важно. Prefetch намеренно имеет низкий приоритет. Браузер может загрузить его во время простоя и сохранить для последующего использования. Он также может пропустить его на плохом соединении, в режимах экономии данных или при нехватке памяти.

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

Хорошие кандидаты для prefetch:

  • Следующий шаг в многостраничном checkout.
  • Search results после того, как пользователь начал вводить query, если следующий route предсказуем.
  • Documentation pages, связанные из table of contents, когда пользователь активно читает близкий контент.
  • Route chunks в single-page app после того, как пользователь навел курсор на navigation item или сфокусировался на нем.

Плохие кандидаты для prefetch:

  • Все ваше navigation tree.
  • Большие videos или image galleries.
  • Third-party scripts “на всякий случай”.
  • Страницы, на которые пользователи редко переходят следующими.

Prefetch — это место, где сдержанность окупается. Ресурс, загруженный и ни разу не использованный, не бесплатен. Он потребляет bandwidth, server capacity, energy и, возможно, пользовательские данные. В мобильных сетях speculative fetching может быть прямо недружелюбным.

Для многих сайтов лучшая стратегия prefetch — intent-based. Не prefetch страницу pricing сразу после загрузки home page. Prefetch ее, когда пользователь открывает pricing menu, наводит курсор на pricing link или прокручивает до call-to-action, который сильно предсказывает переход.

Также помните, что поведение браузеров различается. Некоторые браузеры консервативны с prefetch; некоторые настройки privacy уменьшают или отключают speculative loading. Рассматривайте prefetch как оппортунистическое улучшение, а не как механизм корректности.

Preconnect: для дорогих соединений с важными origins

preconnect говорит браузеру: “Начни устанавливать соединение с этим origin сейчас”.

Это может включать DNS lookup, TCP connection и TLS negotiation. Для сторонних origins такая подготовка может занимать сотни миллисекунд, особенно в сетях с высокой задержкой. Если странице скоро понадобится критический запрос к этому origin, preconnect может ускорить последующий запрос.

Пример:

<link rel='preconnect' href='https://fonts.gstatic.com' crossorigin>

Хорошие кандидаты для preconnect:

  • Font origin, используемый для render-blocking text.
  • Критический API origin, нужный во время начального взаимодействия.
  • CDN origin, отдающий above-the-fold assets.
  • Payments или identity provider, нужный сразу после действия пользователя.

Плохие кандидаты для preconnect:

  • Analytics и advertising endpoints, которые не критичны для пользователя.
  • Origins, используемые только в некоторых сессиях.
  • Длинные списки сторонних сервисов.
  • Same-origin resources, для которых браузер уже имеет или скоро откроет соединение.

У preconnect есть стоимость удержания. Открытые sockets потребляют память и сетевые ресурсы. Браузеры закрывают неиспользуемые соединения, но это не делает ненужные preconnect безвредными.

Полезное правило: preconnect не более чем к одному-двум high-confidence сторонним origins на странице. Если хочется добавить больше, вашей third-party architecture, вероятно, нужен пересмотр больше, чем вашим подсказкам — расширение.

DNS-prefetch: более легкий родственник

Вы также можете встретить dns-prefetch:

<link rel='dns-prefetch' href='https://example-cdn.com'>

Он только разрешает доменное имя. Он не открывает TCP или TLS connection. Это дешевле, чем preconnect, но и менее полезно.

DNS-prefetch может быть разумен для lower-confidence сторонних origins, где полный preconnect кажется слишком агрессивным. На практике, если origin критичен и точно скоро будет использован, предпочтите preconnect. Если это лишь возможно, используйте DNS-prefetch или не делайте ничего.

Как решить: практический workflow

Начинайте с измерения, а не с тегов.

1. Найдите узкое место

Откройте performance trace и ищите позднее обнаружение. Запрос font, hero image или script стартовал только после того, как другой файл был загружен и распарсен? Это кандидат на preload.

Если запрос стартует только после долгой подготовки DNS/TCP/TLS к стороннему origin, это кандидат на preconnect.

Если текущая страница в порядке, но следующий переход предсказуемо медленный, prefetch может помочь.

2. Добавляйте по одной подсказке

Resource hints взаимодействуют. Добавьте одну, протестируйте ее и оставьте только если waterfall улучшился, а пользовательские метрики не ухудшились.

Для preload следите, действительно ли подсказанный ресурс вскоре используется. Chrome может предупреждать, когда preloaded resource не используется вскоре после загрузки. Отнеситесь к этому предупреждению серьезно.

3. Проверяйте побочные эффекты приоритетов

Preload может отнять bandwidth у CSS, JavaScript или images, которые важнее. Preconnect может занять connection slot. Prefetch может добавить фоновый traffic.

Правильный результат — не “подсказанный файл стартует раньше”. Правильный результат — “страница становится заметно лучше для пользователей”. Смотрите на LCP, INP, CLS и real-user monitoring, где это возможно.

4. Проверяйте headers и caching

Hints можно отправлять в HTML или HTTP Link headers. Headers полезны, когда server заранее знает, что понадобится странице, но их сложнее просматривать мимоходом. Если вы отлаживаете, присутствует ли подсказка в production, raw headers важны; именно такие ситуации разобраны в нашем руководстве по отладке redirects и HTTP headers.

Caching тоже важен. Preload ресурса с несовпадающими credentials, неправильным as или отличающимися URL parameters может вызвать duplicate downloads. Это один из самых распространенных способов превратить preload с добрыми намерениями в performance bug.

Распространенные ошибки

Preload слишком многого

Если все критично, не критично ничего. Ограничьте preload ресурсами, нужными для начального рендеринга или немедленной интерактивности. У типичной страницы должно быть от нуля до трех preloads, а не двадцать.

Использование prefetch для обязательных ресурсов

Prefetch имеет низкий приоритет и необязателен. Не используйте его для assets, необходимых текущей странице. Если странице нужен ресурс сейчас, рассмотрите preload или обычное обнаружение через HTML.

Preconnect к каждой третьей стороне

Страницы с большим количеством third-party часто имеют десять и более внешних origins. Preconnect ко всем создает шум. Выберите один или два, которые одновременно критичны и предсказуемо используются.

Игнорирование мобильных условий

Resource hints наиболее ценны на более медленных соединениях, но там же они наиболее опасны. Потраченный впустую prefetch на быстром desktop connection — погрешность округления. На ограниченном мобильном тарифе это плохой компромисс.

Простая таблица решений

| Situation | Best hint | Why | |---|---:|---| | Критический font обнаруживается через CSS | preload | Текущей странице он нужен, обнаружение позднее | | Hero image скрыт за CSS или client rendering | preload | Может улучшить LCP, если image стартует поздно | | Вероятный следующий route после намерения пользователя | prefetch | Помогает будущей навигации, не блокируя текущую страницу | | Критический сторонний font/API origin | preconnect | Убирает установку соединения из critical path | | Возможный, но неопределенный сторонний origin | dns-prefetch or none | Ниже стоимость, ниже уверенность | | Below-the-fold image | none | Позвольте lazy loading и приоритетам браузера работать |

Спокойное правило

Resource hints работают лучше всего, когда они скучны и конкретны. Один font. Один LCP image. Один важный сторонний origin. Один вероятный следующий route после намерения.

Они работают плохо, когда используются как оптимизм: возможно, пользователю это понадобится, возможно, браузеру стоит это загрузить, возможно, больше подсказок означает больше скорости.

Браузеры уже активно оптимизируют. Ваша задача — не микроменеджить каждый запрос. Ваша задача — исправить те немногие случаи, где браузеру не хватает информации в нужный момент.

Часто задаваемые вопросы

Стоит ли preload все мои fonts?
Нет. Preload только те файлы font, которые рано нужны для видимого текста на странице. Preload каждого weight и style обычно тратит bandwidth впустую и может задерживать более важные ресурсы.
Безопасно ли использовать prefetch для каждой внутренней ссылки?
Обычно нет. Это может создавать ненужный фоновый traffic и расходовать пользовательские данные. Предпочитайте intent-based prefetching: например, после hover, focus, открытия menu или на предсказуемом следующем шаге.
В чем разница между preconnect и dns-prefetch?
Preconnect выполняет DNS, TCP и TLS setup для origin. DNS-prefetch только разрешает доменное имя. Preconnect сильнее, но дороже, поэтому его следует использовать с большей уверенностью.
Могут ли resource hints улучшить Core Web Vitals?
Да, особенно LCP, когда они исправляют позднее обнаружение или установку соединения для критического ресурса. Они не помогут, если реальная проблема — oversized assets, медленный server response, render-blocking code или плохое caching.
Resource hints лучше добавлять в HTML или HTTP headers?
Оба варианта могут работать. HTML проще осмысливать для page-specific hints. HTTP Link headers могут быть полезны, когда server знает критические ресурсы до парсинга HTML, но они требуют тщательного тестирования, чтобы избежать duplicates или stale hints.

Источники и дальнейшее чтение

  1. MDN: rel=preload
  2. MDN: Resource hints
  3. web.dev: Preconnect and DNS-prefetch
  4. W3C: Resource Hints
Об авторе
The Wux Webtools Team

Последнее обновление:

Продолжайте читать

Web Performance

Почему вашему сайту стоит отправлять меньше запросов, а не просто уменьшать их размер

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

2 минуты чтения