🎉 Первое видео: Интервью с разработчиком из Meta

Resource Loading Strategies - preload, prefetch, modulepreload

Resource Loading Strategies — это набор техник для оптимизации загрузки ресурсов в браузере. Правильное использование preload, prefetch и других hint'ов может значительно ускорить загрузку страницы.

Спектр стратегий загрузки

Preload — Загрузи это немедленно!

Назначение: Загрузить критически важный ресурс как можно раньше.

Синтаксис Preload

<!-- Критические шрифты -->
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>

<!-- Критический CSS -->
<link rel="preload" href="/critical.css" as="style">

<!-- Hero image -->
<link rel="preload" href="/hero.jpg" as="image">

<!-- JavaScript module -->
<link rel="preload" href="/app.js" as="script">

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

Хорошо:

<!-- Шрифты, используемые в critical CSS -->
<link rel="preload" href="/fonts/heading.woff2" as="font" crossorigin>

<!-- LCP image (Largest Contentful Paint) -->
<link rel="preload" href="/hero-image.jpg" as="image">

<!-- Critical CSS (above the fold) -->
<link rel="preload" href="/above-fold.css" as="style">

Плохо:

<!-- Не preload'ить всё подряд! -->
<link rel="preload" href="/image1.jpg" as="image">
<link rel="preload" href="/image2.jpg" as="image">
<link rel="preload" href="/image3.jpg" as="image">
<!-- Это замедляет загрузку! -->

Типы ресурсов (as attribute)

TypeПример
scriptJavaScript файлы
styleCSS файлы
fontШрифты (требует crossorigin)
imageИзображения
fetchAPI запросы, JSON
videoВидео файлы
audioАудио файлы

Prefetch — Загрузи когда освободишься

Назначение: Загрузить ресурс для следующей навигации (низкий приоритет).

Синтаксис Prefetch

<!-- Страница, куда пользователь, вероятно, перейдёт -->
<link rel="prefetch" href="/next-page.html">

<!-- JavaScript для следующей страницы -->
<link rel="prefetch" href="/next-page.js">

<!-- Изображения, которые появятся при скролле -->
<link rel="prefetch" href="/below-fold-image.jpg">

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

Хорошо:

<!-- На странице продукта - prefetch корзины -->
<link rel="prefetch" href="/cart.js">

<!-- На landing page - prefetch signup page -->
<link rel="prefetch" href="/signup">

<!-- В карусели - prefetch следующего изображения -->
<link rel="prefetch" href="/carousel-image-2.jpg">

Плохо:

<!-- Не prefetch критические ресурсы текущей страницы! -->
<link rel="prefetch" href="/hero-image.jpg"> <!-- Должен быть preload! -->

Modulepreload — Preload для ES modules

Назначение: Preload для JavaScript модулей + их зависимостей.

Синтаксис Modulepreload

<!-- Загрузить модуль и его dependencies -->
<link rel="modulepreload" href="/app.js">

<!-- Это также загрузит импорты внутри app.js: -->
<!-- import { utils } from './utils.js' -->
<!-- import { api } from './api.js' -->

Преимущества Modulepreload

// app.js
import { helper } from './helper.js';
import { api } from './api.js';

// Без modulepreload:
// 1. Загрузить app.js
// 2. Парсить app.js
// 3. Обнаружить импорты
// 4. Загрузить helper.js и api.js  Задержка!

// С modulepreload:
// 1. Параллельно загрузить app.js, helper.js, api.js
// 2. Парсить и выполнить

DNS-Prefetch — Резолв DNS заранее

Назначение: Выполнить DNS lookup для внешнего домена.

Синтаксис DNS-Prefetch

<!-- Внешние ресурсы -->
<link rel="dns-prefetch" href="https://fonts.googleapis.com">
<link rel="dns-prefetch" href="https://cdn.example.com">
<link rel="dns-prefetch" href="https://analytics.google.com">

Экономия времени:

Без dns-prefetch:
User action → DNS lookup (20-120ms) → Connect → Request

С dns-prefetch:
DNS уже готов! → Connect → Request
Экономия: 20-120ms

Preconnect — Установи соединение заранее

Назначение: DNS + TCP + TLS handshake для внешнего домена.

Синтаксис Preconnect

<!-- Критические внешние ресурсы -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://cdn.example.com">

Что включает preconnect

1. DNS lookup     (20-120ms)
2. TCP handshake  (RTT)
3. TLS handshake  (RTT)
----------------------------
Total savings: 100-500ms!

Preconnect vs DNS-Prefetch

dns-prefetchpreconnect
DNS lookupДаДа
TCP handshakeНетДа
TLS handshakeНетДа
CostДешевоДороже
WhenМного доменовКритические домены (2-3)

Priority Hints (приоритеты загрузки)

Attribute fetchpriority управляет приоритетом загрузки:

<!-- Высокий приоритет для LCP image -->
<img src="/hero.jpg" fetchpriority="high">

<!-- Низкий приоритет для below-fold image -->
<img src="/footer-logo.jpg" fetchpriority="low" loading="lazy">

<!-- Критический CSS -->
<link rel="stylesheet" href="/critical.css" fetchpriority="high">

<!-- Некритический JavaScript -->
<script src="/analytics.js" fetchpriority="low" async></script>

Приоритеты браузера (по умолчанию)

РесурсПриоритет
HTMLHighest
CSS (в <head>)Highest
FontsHigh
Scripts (в <head>)High
Images (в viewport)High
Scripts (async)Low
Images (below fold)Low

Critical Request Chains

Цепочка критических запросов — последовательность блокирующих ресурсов:

<!-- Плохо: глубокая цепочка -->
<html>
<head>
  <link rel="stylesheet" href="/style.css">
  <!-- В style.css: -->
  <!-- @import url('/fonts.css'); -->
  <!-- В fonts.css: -->
  <!-- @font-face { src: url('/font.woff2'); } -->
</head>

Depth = 3:

  1. Загрузить style.css
  2. Парсить → найти fonts.css → загрузить
  3. Парсить → найти font.woff2 → загрузить

Решение:

<!-- Хорошо: параллельная загрузка -->
<head>
  <link rel="preload" href="/font.woff2" as="font" crossorigin>
  <link rel="stylesheet" href="/style.css">
</head>
<!-- Depth = 1, всё параллельно! -->

Практические примеры

E-commerce сайт

<head>
  <!-- Critical для LCP -->
  <link rel="preload" href="/hero-product.jpg" as="image" fetchpriority="high">
  <link rel="preload" href="/fonts/main.woff2" as="font" crossorigin>
  
  <!-- Внешние критические ресурсы -->
  <link rel="preconnect" href="https://cdn.shopify.com">
  
  <!-- Некритические внешние -->
  <link rel="dns-prefetch" href="https://analytics.google.com">
  
  <!-- Prefetch для вероятного перехода -->
  <link rel="prefetch" href="/cart">
  <link rel="prefetch" href="/checkout.js">
</head>

SPA (Single Page Application)

<!-- Preload critical chunks -->
<link rel="modulepreload" href="/app.js">
<link rel="modulepreload" href="/router.js">

<!-- Prefetch route chunks -->
<link rel="prefetch" href="/routes/home.js">
<link rel="prefetch" href="/routes/about.js">

Best Practices

1

Preload только критические ресурсы

Максимум 3-5 preload'ов. Больше = конкуренция за bandwidth.

2

Prefetch для предсказуемой навигации

Анализируйте user journey и prefetch'ите вероятные переходы.

3

Preconnect для критических CDN

Не больше 2-3 preconnect (дорогая операция).

4

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

Помогите браузеру приоритизировать LCP ресурсы.

5

Измеряйте impact

Используйте Lighthouse, WebPageTest для валидации.

Инструменты для анализа

Chrome DevTools

Network tab → Priority column
Высокий = Critical Path
Низкий = Prefetch candidates

Lighthouse

- "Preload key requests"
- "Reduce initial server response time"
- "Eliminate render-blocking resources"

Итог:

Правильное использование resource hints (preload, prefetch, preconnect) может сократить время загрузки на 20-50%. Ключ — понимание Critical Path и user journey. Preload для критических ресурсов, prefetch для вероятных переходов, preconnect для внешних API/CDN.

Связанные статьи