Kodokon kodokon.com

Производительность загрузки: defer, async, preload и prefetch

Управляй порядком выполнения скриптов через defer и async, а затем направляй сеть с помощью preload, preconnect и prefetch.

10 мин · 3 вопросов

Открыть этот урок в Kodokon

Обычный <script src> блокирует разбор HTML: браузер останавливается, скачивает, выполняет и только потом продолжает. Два атрибута меняют правила игры. defer скачивает параллельно разбору и выполняет скрипты в порядке документа, прямо перед DOMContentLoaded: это выбор по умолчанию для кода твоего приложения, который может зависеть от DOM и от других скриптов. async тоже скачивает параллельно, но выполняет сразу, как только файл придёт, без гарантии порядка: оставь его для самостоятельных скриптов вроде аналитики, которые ни от чего не зависят.

HTML
<script src="/js/analytics.js" async></script>
<script src="/js/vendor.js" defer></script>
<script src="/js/app.js" defer></script>
vendor.js всегда выполнится раньше app.js

Некоторые критичные ресурсы браузер обнаруживает совсем поздно: шрифт, указанный внутри CSS-файла, изображение, загружаемое из JavaScript. <link rel="preload"> решает эту проблему позднего обнаружения, объявляя ресурс прямо в <head>, с обязательным атрибутом as, чтобы браузер применил правильный приоритет и правильный кеш. Хрестоматийный случай - веб-шрифты, которые иначе запрашиваются только после того, как CSS скачан и разобран.

HTML
<link rel="preload" as="font" type="font/woff2"
      href="/fonts/inter-var.woff2" crossorigin>
<link rel="preload" as="image"
      href="/img/hero-1600.jpg" fetchpriority="high">
Раннее обнаружение шрифта и изображения LCP

Последнее семейство - низкоприоритетные сетевые подсказки. <link rel="preconnect"> заранее устанавливает полное соединение (DNS, TCP, TLS) со сторонним источником, который ты точно будешь использовать: до 300 мс экономии на первом запросе. dns-prefetch - его облегчённый родственник (только разрешение DNS), полезен как запасной вариант для менее очевидных источников. А prefetch скачивает в моменты простоя ресурс, предназначенный для следующего перехода: например, страницу оформления заказа из корзины. Компромисс очевиден: preload служит текущей странице, prefetch ставит на следующую.

HTML
<link rel="preconnect"
      href="https://api.example.com">
<link rel="dns-prefetch"
      href="https://cdn.example.com">
<link rel="prefetch" href="/checkout.html">
Заблаговременные соединения и ставка на следующий переход

Проверка знаний

Убедись, что запомнил ключевые моменты этого урока.

  1. Какую гарантию даёт defer, которой нет у async?
    • Скачивание параллельно с разбором HTML
    • Выполнение в порядке документа, до DOMContentLoaded
    • Выполнение до какой-либо отрисовки страницы
  2. Почему crossorigin обязателен при preload шрифта с того же источника?
    • Шрифты всегда запрашиваются в режиме CORS; без него файл скачивается дважды
    • Это требование безопасности формата WOFF2
    • Без него preload блокируется политикой CSP по умолчанию
  3. Как правильно использовать rel="prefetch"?
    • Ускорить критичный ресурс на текущей странице
    • Скачать с низким приоритетом ресурс, вероятно нужный при следующем переходе
    • Заставить браузер кешировать файл навсегда