Скрипты — атрибуты async и defer

23.05.2022

Теги: FrontendJavaScriptWeb-разработкаДокументТеория

Когда браузер загружает HTML и доходит до тега <script>…<script>, он не может продолжать строить DOM. Он должен сначала выполнить скрипт. То же самое происходит и с внешними скриптами <script src="…"></script> — браузер должен подождать, пока загрузится скрипт, выполнить его, и только затем обработать остальную страницу.

Это ведёт к двум важным проблемам:

  • Скрипты не видят DOM-элементы ниже себя, поэтому к ним нельзя добавить обработчики и т.д.
  • Если вверху страницы объёмный скрипт, он «блокирует» страницу на время загрузки и выполнения.

Конечно, есть пути, как это обойти. Например, мы можем поместить скрипт внизу страницы. Тогда он сможет видеть элементы над ним и не будет препятствовать отображению содержимого страницы.

<body>
    <header>...</header>
    <main>...</main>
    <footer>...</footer>

    <script src="..."></script>
</body>

Но это решение далеко от идеального. Например, браузер замечает скрипт (и может начать загружать его) только после того, как он полностью загрузил HTML-документ. В случае с длинными HTML-страницами это может создать заметную задержку.

К счастью, есть два атрибута тега <script>, которые решают нашу проблему — defer и async.

defer

Атрибут defer сообщает браузеру, что он должен продолжать обрабатывать страницу и загружать скрипт в фоновом режиме, а затем запустить этот скрипт, когда DOM дерево будет полностью построено. Важный момент — скрипт с атрибутом defer всегда выполняются, когда дерево DOM готово, но до события DOMContentLoaded.

Отложенные с помощью defer скрипты сохраняют порядок относительно друг друга, как и обычные скрипты. Поэтому, если сначала в html-коде идет большой скрипт, а затем маленький — то последний будет ждать окончания загрузки и выполнения первого. Спецификация требует последовательного выполнения скриптов согласно порядку в документе.

<script defer src="large.js"></script>
<script defer src="small.js"></script>

async

Атрибут async означает, что скрипт абсолютно независим:

  • Содержимое страницы отображается сразу же — async его не блокирует.
  • DOMContentLoaded может произойти как до, так и после async, никаких гарантий нет.
  • Асинхронные скрипты не ждут друг друга. Меньший скрипт small.js идёт вторым, но скорее всего загрузится раньше large.js, поэтому и запустится первым. То есть, скрипты выполняются в порядке загрузки.

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

<!-- Типичное подключение скрипта Google Analytics -->
<script async src="https://google-analytics.com/analytics.js"></script>

Динамически загружаемые скрипты

Мы можем также добавить скрипт и динамически, с помощью js-кода:

let script = document.createElement('script');
script.src = 'large.js';
document.body.append(script);

Динамически загружаемый скрипт по умолчанию ведет себя как «async» — начинает загружаться, как только он будет добавлен в документ:

  • Сам скрипт никого не ждет, и его никто не ждёт
  • Если первым загрузился — первым и запустился

Мы можем изменить относительный порядок скриптов с «первый загрузился — первый выполнился» на порядок, в котором они идут в документе (как в обычных скриптах) с помощью явной установки свойства async в false.

function loadScript(src) {
    let script = document.createElement('script');
    script.src = src;
    script.async = false;
    document.body.append(script);
}

// large.js запускается первым, так как async=false
loadScript('large.js');
loadScript('small.js');

Поиск: Frontend • JavaScript • Web-разработка • Документ • Теория

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.