Атрибут defer в HTML
Атрибут defer в HTML указывает, что скрипт выполняется после завершения разбора страницы. Узнайте, как использовать его в элементе <script>.
Атрибут HTML defer — это boolean-атрибут элемента <script>, который указывает браузеру загружать скрипт параллельно с разбором HTML, но ждать и выполнять его только после полного завершения разбора страницы — непосредственно перед тем, как сработает событие DOMContentLoaded.
Он работает только с внешними скриптами: эффект проявляется, лишь когда присутствует атрибут src, а на встроенных скриптах (тех, чей JavaScript написан между тегами <script>) атрибут игнорируется.
Зачем нужен атрибут defer
Обычный тег <script src="..."> блокирует рендеринг. Когда парсер встречает его, он останавливает построение страницы, скачивает файл, выполняет его и только потом продолжает работу. Если скрипт находится в <head>, пользователь видит пустую страницу до тех пор, пока файл не загрузится.
Классическим обходным решением было помещать теги <script> в самый конец <body>, чтобы HTML разбирался первым. Атрибут defer делает этот приём ненужным: можно оставлять скрипты в <head> (удобно для читаемости и для того, чтобы браузер обнаруживал и загружал их раньше), при этом скрипт всё равно выполнится только после полного построения DOM. Поскольку DOM гарантированно готов, отложенные скрипты могут безопасно обращаться к элементам без необходимости оборачивать всё в обработчик DOMContentLoaded.
defer и async
Оба атрибута — defer и async — позволяют браузеру загружать скрипт в фоне, не блокируя разбор HTML. Разница состоит в том, когда и в каком порядке выполняются скрипты:
| Поведение | defer | async |
|---|---|---|
| Блокирует разбор HTML во время загрузки | Нет | Нет |
| Когда выполняется скрипт | После завершения разбора, непосредственно перед DOMContentLoaded | Как только завершится загрузка (может прервать разбор) |
| Порядок выполнения относительно других скриптов | Сохраняется — выполняется в порядке документа | Не гарантируется — первым выполняется тот, что загрузится раньше |
| DOM гарантированно готов | Да | Нет |
Используйте defer, когда скрипты зависят от DOM или друг от друга (порядок важен). Используйте async для независимых, самодостаточных скриптов — например, аналитики или рекламных тегов, — где порядок не имеет значения и каждый должен выполняться сразу по прибытии.
Если не указан ни async, ни defer, скрипт загружается и выполняется немедленно, блокируя парсер в этой точке.
В HTML 4.01 поведение defer зависело от реализации, тогда как HTML5 стандартизировал его. В XHTML атрибут defer необходимо записывать как <script defer="defer">, поскольку сокращённая запись атрибутов запрещена.
Синтаксис
<script src="example.js" defer></script>Пример атрибута defer в HTML
Скрипт ниже помещён в <head>, однако благодаря отложенному выполнению он запускается лишь после того, как абзац появится в DOM, — поэтому document.getElementById находит его:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"
defer
></script>
<noscript>Sorry, your browser doesn't support JavaScript!</noscript>
</head>
<body>
<h1>Example</h1>
<p id="demo">Waiting for the deferred script...</p>
<script defer>
// This deferred external script (jQuery) is already loaded,
// and the DOM is fully parsed, so the line below works.
document.getElementById("demo").textContent =
"jQuery version " + jQuery.fn.jquery + " ran after parsing.";
</script>
</body>
</html>Примечание: атрибут
deferу встроенного тега<script>выше игнорируется — встроенные скрипты всегда выполняются на месте. Здесь всё работает лишь потому, что этот тег стоит последним и отложенный внешний скрипт уже загружен. Чтобы гарантировать, что отложенная внешняя библиотека загрузится раньше вашего собственного кода, перенесите свой код тоже в отдельный внешний файл сdefer, поскольку отложенные скрипты выполняются в порядке документа.