Defer js что это

How and when to use Async and Defer attributes

Both async and defer attributes look like they do the same thing at first glance, but there are nuances to async and defer . Most of the time, you’d want to use defer instead of async , even though async sounds sexier.

I’d like to walk you through the differences and why you should use them (and also why you don’t have to use them).

Why use async or defer in the first place?

When the browser comes across a <script> tag when loading HTML, the browser is forced to download parse the entire <script> and evaluate it first, before it can continue with reading the rest of the HTML to build the DOM.

This means the normal <script> tag is blocking and can cause the DOM to stop loading.

Here’s an example where I deliberately created a script with 20000 lines of console.log statements within long.js . This stalls the loading of the rest of the page

Your browser does not support the video tag. Watch the video here instead.

Both async and defer allows the browser load and parse the JavaScript file separately, so the DOM can be shown immediately. This allows users to see content faster.

Your browser does not support the video tag. Watch the video here instead.

We can still put scripts normally at the bottom

Since a script is blocking, it became a best practice to put all scripts at the bottom of the page.

This practice still works. We don’t have to get fancy with async and defer attributes if you don’t want to. Feel free to continue using the old-school method without feeling guilty!

Async vs Defer

Both async and defer load scripts without blocking the DOM, but there are two differences between async and defer .

Defer waits for the DOM. Async doesn’t.

The first difference is async doesn’t care whether the DOM is fully loaded. defer waits for DOM to be loaded before it executes.

  • You should use defer if your script requires the DOM.
  • If you use async and you need the DOM, you run the risk that the element you need cannot be found (which is a potential source of bugs).

Regarding the second point, the risk happens when you have a large DOM to parse through. For example, say you have 20,000 button elements and you want to select them all. defer would ensure all 20000 elements are selected. But async would select as many elements as there are when the async -ed script is fully loaded.

Number of elements selected by async and defer

Defer respects the sequence of scripts. Async doesn’t.

We can prove this with another example. We’ll have three scripts. Each script logs a number into the console. If we slap async into the scripts, the loading order becomes unpredictable.

Loading order of async

But if we use defer the loading order will always be as specified

Loading order of defer

When to use async

You should use async if your script contains the following conditions:

  • The DOM you need is already present (or the script doesn’t need the DOM)
  • The script doesn’t depend on other scripts

People normally say analytics is a good case for async scripts. I disagree. async is only good for analytics when you’re using it for simple analytics like tracking page loads. We cannot rely on async if we want to track events like button clicks that require the DOM. In such cases, I prefer to use defer instead.

Loading scripts in the middle

async is great for loading scripts in the middle of the DOM if you have to. Since the DOM is already present, the script can be executed immediately without problems.

One example here is my newsletter signup form (which is powered by Convertkit). I load this newsletter form via the async attribute because I want it to show as soon as possible. It works because all necessary elements are already present.

That said, do this kinda scripts-in-the-middle style sparingly. If your scripts are all over the place, it becomes really hard to remember where you placed your scripts.

When to use defer

You should use defer for all other scripts. defer is great because it:

  • Gets loaded as soon as possible — so it reduces load times.
  • Doesn’t execute until everything you need is ready — so all the DOM you need is there
  • Follows script order — allows you to structure which script comes first

New-age loading

Since defer loads scripts in the order specified, and it only executes scripts after the DOM is loaded, we can safely substitute defer as the best-practice default going forward.

This is practically the same as the old method — but it has the benefit that scripts are loaded first and asynchronously, which means faster execution overall!

When we do this, we can keep all scripts (including CSS) at the <head> which creates a cleaner HTML overall.

Wrapping up

Practically, defer is more useful, but async sounds sexier . Most of the time you’d want defer instead of async .

If you enjoyed this article, please support me by sharing this article Twitter or buying me a coffee . If you spot a typo, I’d appreciate if you can correct it on GitHub. Thank you!

Скрипты: async, defer

В современных сайтах скрипты обычно «тяжелее», чем HTML: они весят больше, дольше обрабатываются.

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

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

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

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

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

Такие вещи незаметны людям, у кого очень быстрое соединение, но много кто в мире имеет медленное подключение к интернету или использует не такой хороший мобильный интернет.

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

defer

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

Вот тот же пример, что и выше, но с defer :

  • Скрипты с defer никогда не блокируют страницу.
  • Скрипты с defer всегда выполняются, когда дерево DOM готово, но до события DOMContentLoaded .

Следующий пример это показывает:

  1. Содержимое страницы отобразится мгновенно.
  2. Событие DOMContentLoaded подождёт отложенный скрипт. Оно будет сгенерировано, только когда скрипт (2) будет загружен и выполнен.

Отложенные с помощью defer скрипты сохраняют порядок относительно друг друга, как и обычные скрипты.

Поэтому, если сначала загружается большой скрипт, а затем меньшего размера, то последний будет ждать.

Браузеры сканируют страницу на предмет скриптов и загружают их параллельно в целях увеличения производительности. Поэтому и в примере выше оба скрипта скачиваются параллельно. small.js скорее всего загрузится первым.

Но спецификация требует последовательного выполнения скриптов согласно порядку в документе, поэтому он подождёт выполнения long.js .

Атрибут defer будет проигнорирован, если в теге <script> нет src .

async

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

  • Страница не ждёт асинхронных скриптов, содержимое обрабатывается и отображается.
  • Событие DOMContentLoaded и асинхронные скрипты не ждут друг друга:
    • DOMContentLoaded может произойти как до асинхронного скрипта (если асинхронный скрипт завершит загрузку после того, как страница будет готова),
    • …так и после асинхронного скрипта (если он короткий или уже содержится в HTTP-кеше)

    Так что если у нас есть несколько скриптов с async , они могут выполняться в любом порядке. То, что первое загрузится – запустится в первую очередь:

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

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

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

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

    Скрипт начнёт загружаться, как только он будет добавлен в документ (*) .

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

    • Они никого не ждут, и их никто не ждёт.
    • Скрипт, который загружается первым – запускается первым (в порядке загрузки).

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

    Например, здесь мы добавляем два скрипта. Без script.async=false они запускались бы в порядке загрузки ( small.js скорее всего запустился бы раньше). Но с этим флагом порядок будет как в документе:

    Итого

    У async и defer есть кое-что общее: они не блокируют отрисовку страницы. Так что пользователь может просмотреть содержимое страницы и ознакомиться с ней сразу же.

    Но есть и значимые различия:

    Порядок DOMContentLoaded
    async Порядок загрузки (кто загрузится первым, тот и сработает). Не имеет значения. Может загрузиться и выполниться до того, как страница полностью загрузится. Такое случается, если скрипты маленькие или хранятся в кеше, а документ достаточно большой.
    defer Порядок документа (как расположены в документе). Выполняется после того, как документ загружен и обработан (ждёт), непосредственно перед DOMContentLoaded .

    Пожалуйста, помните, что когда вы используете defer , страница видна до того, как скрипт загрузится.

    Пользователь может знакомиться с содержимым страницы, читать её, но графические компоненты пока отключены.

    Поэтому обязательно должна быть индикация загрузки, нерабочие кнопки – отключены с помощью CSS или другим образом. Чтобы пользователь явно видел, что уже готово, а что пока нет.

    На практике defer используется для скриптов, которым требуется доступ ко всему DOM и/или важен их относительный порядок выполнения.

    А async хорош для независимых скриптов, например счётчиков и рекламы, относительный порядок выполнения которых не играет роли.

    Асинхронный JavaScript против отложенного

    В моей статье «Понимание критического пути рендеринга» (перевод статьи) я писала о том, какой эффект оказывают JavaScript-файлы на Критический Путь Рендеринга(CRP).

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

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

    Нормальное выполнение

    Прежде чем понять разницу между этими двумя атрибутами, давайте посмотрим что происходит в их отсутствие. Как было сказано ранее, по умолчанию файлы JavaScript прерывают парсинг HTML-документа до тех пор, пока не будут получены и выполнены.
    Возьмём пример, в котором элемент <script> расположен где-то в середине страницы:

    Вот что произойдёт, когда парсер будет обрабатывать документ:

    Парсинг HTML приостанавливается, пока скрипт не будет загружен и выполнен, тем самым увеличивая количество времени до первой отрисовки.

    Атрибут async

    Async используется для того, чтобы указать браузеру, что скрипт может быть выполнен асинхронно.
    Парсеру HTML нет необходимости останавливаться, когда он достигает тега <script> для загрузки и выполнении. Выполнение может произойти после того, как скрипт будет получен параллельно с разбором документа.

    Атрибут доступен только для файлов, подключающихся внешне. Если внешний файл имеет этот атрибут, то он может быть загружен в то время как HTML-документ ещё парсится. Парсер будет приостановлен для выполнения скрипта, как только файл скрипта будет загружен.

    Атрибут defer

    Атрибут defer указывает браузеру, что скрипт должен быть выполнен после того, как HTML-документ будет полностью разобран.

    Как и при асинхронной загрузке скриптов — файл может быть загружен, в то время как HTML-документ парсится. Однако, даже если файл скрипта будет полностью загружен ещё до того, как парсер закончит работу, он не будет выполнен до тех пор, пока парсер не отработает до конца.

    Асинхронное, отложенное или нормальное выполнение?

    Итак, когда же следует использовать асинхронное, отложенное или нормальное выполнение JavaScript? Как всегда, это зависит от ситуации и существуют несколько вопросов, которые помогут принять вам правильное решение.

    Где расположен элемент <script> ?

    Асинхронное и отложенное выполнения наиболее важны, когда элемент <script> не находится в самом конце документа. HTML-документы парсятся по порядку, с открытия <html> до его закрытия. Если внешний JavaScript-файл размещается непосредственно перед закрывающим тегом </body> , то использование async и defer становится менее уместным, так как парсер к тому времени уже разберёт большую часть документа, и JavaScript-файлы уже не будут оказывать воздействие на него.

    Скрипт самодостаточен?

    Для файлов, которые не зависят от других файлов и/или не имеют никаких зависимостей, атрибут async будет наиболее полезен. Поскольку нам не важно, когда файл будет исполнен, асинхронная загрузка — наиболее подходящий вариант.

    Полагается ли скрипт на полностью разобранный DOM?

    Во многих случаях файл скрипта содержит функции, взаимодействующие с DOM. Или, возможно, существует зависимость от другого файла на странице. В таких случаях DOM должен быть полностью разобран, прежде чем скрипт будет выполнен. Как правило, такой файл помещается в низ страницы, чтобы убедиться, что для его работы всё было разобрано. Однако, в ситуации, когда по каким-либо причинам файл должен быть размещён в другом месте — атрибут defer может быть полезен.

    Скрипт небольшой и зависим?

    Наконец, если скрипт является относительно небольшим и/или зависит от других файлов, то, возможно, стоит определить его инлайново. Несмотря на то, что встроенный код блокирует разбор HTML-документа, он не должен сильно помешать, если его размер небольшой. Кроме того, если он зависит от других файлов, может понадобиться незначительная блокировка.

    Поддержка и современные браузерные движки

    Поддержка атрибутов async и defer очень распространена:

    Стоит отметить, что поведение этих атрибутов может немного отличаться в разных движках JavaScript. Например, в V8 (используется в Chromium), сделана попытка разобрать все скрипты, независимо от их атрибутов, на отдельном выделенном потоке для выполнения скрипта. Таким образом, «блокирующая парсер» природа JavaScript-файлов должна быть минимизирована по умолчанию.

    Знакомство с JavaScript. Подключение к странице

    Александр Мальцев

    JavaScript (сокращённо JS) – это язык программирования , который изначально был придуман для браузера, чтобы придать страницам интерактивность и динамичность .

    Программы написанные на JavaScript называются сценариями или скриптами . Добавление их на страницу выполняется через тег <script> . При этом их можно как непосредственно вставлять на веб-страницу, так и размещать в отдельном файле. Каждый браузер имеет интерпретатор JavaScript, с помощью которого он выполняет этот код.

    Потребность в создании языка программирования для веб-браузера возникла в 90-е годы. В это время на веб-страницах хотелось делать уже намного больше, чем просто выводить статичный контент.

    Данный язык изначально был создан Бренданом Айком в 1995 году для браузера Netscape и назывался он Mocha. Но после ряда переименований он обрёл окончательное имя – JavaScript . В начале он имел очень маленькую функциональность и в основном использовался для добавления на страницу интерактивности. Но со временем язык стал развиваться и позволять делать всё больше и больше.

    В 1996 году язык JavaScript был стандартизован компанией Ecma, которая занимается стандартизацией информационных и коммуникационных технологий. Сама спецификация была названа ECMAScript или сокращённо ES. По сути, JavaScript является реализацией спецификации ECMAScript. Новые версии ECMAScript выходят ежегодно и добавляют в язык новые возможности.

    • ECMAScript 1 – июнь 1997;
    • ECMAScript 2 – июнь 1998;
    • ECMAScript 3 – декабрь 1999;
    • ECMAScript 5 – декабрь 2009;
    • ECMAScript 5.1 – июнь 2011;
    • ECMAScript 2015 (ES2015, ECMAScript 6, ES6) – июнь 2015;
    • ECMAScript 2016 (ES2016, ECMAScript 7, ES7) – июнь 2016;
    • ECMAScript 2017 (ES2017, ECMAScript 8, ES8) – июнь 2017;
    • ECMAScript 2018 (ES2018, ECMAScript 9, ES9) – июнь 2018;
    • ECMAScript 2019 (ES2019, ECMAScript 10, ES10) – июнь 2019;
    • ECMAScript 2020 (ES2020, ECMAScript 11, ES11) – июнь 2020;
    • ECMAScript 2021 (ES2021, ECMAScript 12, ES12) – июнь 2021.

    ECMAScript – это стандарт JavaScript, который описывает полностью все функции JavaScript. Браузеры, Node.js применяют это стандарт и реализуют его поддержку.

    Начиная с версии ES6 язык значительно преобразился, в нём появился новый синтаксис для написания сложных приложений (классы, модули, итераторы, циклы, генераторы в стиле Python, стрелочные функции, ключевые слова let , const и многое другое). С выходом версии ES6 весь код JavaScript принято делить на modern (современный) и классический (до ES6) .

    В настоящее время JavaScript применяется не только в веб-браузере. С помощью него можно писать десктопные и мобильные приложения, использовать его на сервере (Node.js).

    Язык JavaScript, как и другие языки программирования, имеет некоторые свои особенности. Среди основных – слабая типизация и динамическое приведение типов .

    JavaScript – это не Java , хоть он и унаследовал некоторые синтаксические конструкции этого языка. Такое название данный язык получил в силу некоторых исторических причин. Одной из них являлось то, что изначально в качестве языка, который должен был быть доступным в браузере, хотели сделать Java . Но впоследствии компания Netscape отказалась от этой мысли, из-за того, что Java был слишком большим и сложным.

    Виды браузеров и браузерных движков

    В настоящее время существует большое количество браузеров . Любой современный браузер основывается на движке . Движок – это часть браузера, которая преобразует HTML, CSS, JavaScript, изображения и другую информацию в интерактивную картинку .

    Основные современные движки и браузеры, которые их используют:

    • Blink (Google Chrome, Opera, Яндекс.Браузер и др.);
    • Gecko (Mozilla Firefox, Waterfox и др);
    • WebKit (Safari, Maxthon, Vivaldi и др.);
    • EdgeHTML (Microsoft Edge).

    Подключение JavaScript к странице

    Добавление JavaScript на страницу выполняется с помощью тега <script> .

    Первый способ – это вставка кода непосредственно на страницу . Выполняется это между открывающим и закрывающим тегом <script> .

    Второй способ заключается в использовании отдельного файла с расширением js . В данный файл необходимо поместить код JavaScript, а затем подключить его к странице с помощью <script> . Путь к файлу задаётся с помощью атрибута src .

    С помощью этого способа можно подключить JavaScript к большому количеству HTML страниц. Это позволяет при изменении кода не править его на каждой странице.

    <script> можно поместить внутрь любого элемента, но рекомендуется непосредственно в <head> или <body> :

    Если подключить скрипт с помощью атрибута src и дополнительно ещё указать некоторый код между открывающим и закрывающим тегом script , то код, который вы указали непосредственно, будет проигнорирован, т.е. он не выполнится.

    Как выполняются скрипты на странице?

    Когда браузер читает страницу и встречает на ней script , он останавливает дальнейшую загрузку страницы и выполняет, подключенный с помощью этого элемента JavaScript. После чего приступает к дальнейшей загрузке страницы:

    В этом примере используются 2 метода:

    • alert() – для вывода на экран предупреждения с кнопкой «ОК»; данное предупреждение приостанавливает дальнейшую загрузку страницу;
    • document.write() – для вывода текста в текущее место HTML, если страница ещё не загрузилась.

    При загрузке этого документа, когда браузер встретит alert() , он выведет на экран предупреждение «HEAD: Hello, world!». Кроме этого, он приостановит дальнейшую загрузку страницы , пока пользователь не нажмёт на кнопку «ОК».

    На этом этапе загрузки страницы:

    Приостановка загрузки веб-страницы и отображение alert сообщения

    После нажатия на кнопку «ОК» браузер продолжит загрузку страницы. Он выполнит метод document.write() , который выведет значение, указанное в скобках сразу после открывающего тега <body> . Затем тег <h1> и в завершении выполнит метод document.write() , который выведет текст «BODY: Hello, world!».

    Полностью загруженная страница

    async и defer

    До появления этих атрибутов у нас не было возможности загружать JavaScript в фоне. Поэтому многие сайты, в которых JavaScript не использовался для формирования первоначальной структуры страницы, подключали его в самом конце, т.е. перед закрывающим тегом <body> . В основном это использовалось для того, чтобы пользователь мог как можно быстрее увидеть страницу и начать с ней взаимодействовать. А так как такой код взаимодействует с уже загруженной страницей, его в принципе и вставлять выше не имеет смысла.

    async – атрибут для <script> , который используется для того, чтобы указать браузеру на то, что этот скрипт необходимо загрузить асинхронно, т.е. не останавливая основной поток чтения страницы. После загрузка скрипта, браузер сразу же его выполнит.

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

    Ещё одно отличие defer от async в том, что defer сохраняет очередность их выполнения:

    Т.е. вне зависимости от того какой скрипт загрузится быстрее, они всё равно будут выполнены браузером в том порядке, в котором они расположены в коде. В данном примере, сначала выполнится «script-1.js», а затем «script-2.js» даже если второй загрузится быстрее, чем первый.

    Если для <script> одновременно указать два атрибута, т.е. сразу async и defer , то будет работать только async .

    Атрибуты async и defer можно использовать только для скриптов, подключаемых на страницу с использованием src .

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *