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 | Пример |
|---|---|
script | JavaScript файлы |
style | CSS файлы |
font | Шрифты (требует crossorigin) |
image | Изображения |
fetch | API запросы, 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-prefetch | preconnect | |
|---|---|---|
| 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>
Приоритеты браузера (по умолчанию)
| Ресурс | Приоритет |
|---|---|
| HTML | Highest |
CSS (в <head>) | Highest |
| Fonts | High |
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:
- Загрузить style.css
- Парсить → найти fonts.css → загрузить
- Парсить → найти 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
Preload только критические ресурсы
Максимум 3-5 preload'ов. Больше = конкуренция за bandwidth.
Prefetch для предсказуемой навигации
Анализируйте user journey и prefetch'ите вероятные переходы.
Preconnect для критических CDN
Не больше 2-3 preconnect (дорогая операция).
Используйте fetchpriority
Помогите браузеру приоритизировать LCP ресурсы.
Измеряйте 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.