Атрибути тега script async і defer. Різниця між async та defer у тега script. Async та Defer - стратегії завантаження JavaScript

Синхронні скрипти - це погано, вони змушують браузер блокувати побудову DOM дерева: спочатку потрібно отримати скрипт, виконати його, а тільки після цього продовжувати обробку частини сторінки, що залишилася. Це, звичайно, вам не новина, і причина, через яку ми, як євангелісти, просували використання асинхронних сценаріїв. Ось простий приклад:

<script src =>script > <script > var script = document .createElement("script"); script.src = "http://somehost.com/awesome-widget.js"; document .getElementsByTagName("head" ).appendChild(script);script >

У чому різниця? У «поганому» варіанті ми блокуємо побудову DOM дерева, чекаємо поки скрипт завантажиться, виконається, а потім продовжуємо обробляти решту документа. У другому прикладі ми відразу починаємо виконувати сценарій, який створює елемент script, що вказує на зовнішній ресурс, додаємо його в документ, і продовжуємо обробку DOM. Відмінність тонка, але дуже важлива: динамічно-створювані скрипти не блокують.

Так, це здорово, вірно? Динамічно-створювані скрипти - це річ! Не так швидко.

JavaScript, що вбудовується, має невеликий, але важливий (і часто не береться до уваги) підводний камінь: CSSOM блокує його перед виконанням. Чому? Браузер не знає, що саме такий скрипт планує зробити, а оскільки JavaScript може маніпулювати CSS властивостями, він блокується і чекає, доки аналізується CSS і будується CSSOM. Краще один раз побачити, ніж сто разів почути, розглянемо наступний приклад:

Почекайте секунду, що відбувається? Обидва сценарії будуть завантажені заздалегідь і виконані через ~2.7 секунд після завантаження сторінки.Зверніть увагу, що скрипти будуть і раніше виконуватися тільки після того, як буде доступний CSS (~2.7 секунди), але оскільки скрипти вже завантажені в той момент, коли стає доступний CSSOM, ми можемо виконувати їх відразу, заощаджуючи більше секунди часу обробки. Ми все робили неправильно?

Перш ніж ми відповімо на це питання, розглянемо ще один приклад, цього разу з атрибутом «async» :

<script src = "http://udacity-crp.herokuapp.com/time.js?rtt=1&a" async >script > <script src = "http://udacity-crp.herokuapp.com/time.js?rtt=1&b" async >script >

За наявності атрибута async скрипт буде виконаний асинхронно, як він буде доступний. Якщо атрибут відсутній, то скрипт завантажується і виконується негайно, перш ніж буде продовжено подальший аналіз документа.

Атрибут async у тезі script реалізує дві важливі властивості: він говорить браузеру, щоб той не блокував побудову DOM і не блокував виконання скриптів перед побудовою CSSOM. В результаті скрипти виконуються відразу після того, як завантажаться (~1.6 секунди), не чекаючи CSSOM. Короткий перелік результатів:

То чому ми досі пропонували використовувати шаблон, який використовує скрипти, що динамічно створюються?

Оригінальна стаття: Script-injected "async scripts" considered harmful Статтю вичитували: visitorFM , zenwalker , FMRobot

The HTML

And the following examples show how to put (an inline) script inside the

Module fallback

Браузери, які підтримують module value для типу atribut ignore any script with nomodule attribute. Що можливі ви використовуєте module scripts while also providing nomodule -marked fallback scripts for non-supporting browsers.

Specifications

Specification Status Comments
HTML Living Standard
The definition of "

У найстаріших версіях IE (6 і нижче) асинхронне завантаження не працює, але таких користувачів вже практично немає. Всі інші браузери та послуги успішно користуються сучасним прискореним завантаженням web-сторінок.

Async та Defer - стратегії завантаження JavaScript


JavaScript є невід'ємною частиною будь-якого сучасного веб-додатка, і стратегії, які ми вирішуємо використовувати для завантаження, безпосередньо впливають на продуктивність роботи цієї програми. У цій статті ми спробуємо зрозуміти важливі відмінності між кожним підходом, плюси та мінуси поряд з наслідками продуктивності та способи оптимізації взаємодії зі сторінкою та часу завантаження.

Для демонстрації я створюю веб-сайт, що складається з наступних зовнішніх залежностей. Зверніть особливу увагу на відповідні розміри файлів, оскільки час завантаження файлів прямо пропорційний цьому.

  • HTML - сторінка ~ 1 МБ. Містить фактичну розмітку/вміст, щоб показати деякі динамічні вихідні дані JavaScript.
  • Зображення - image1.png ~ 5 Мб
  • JavaScript - file1.JS~3 МБ - це ядро ​​(основний файл) javascript і залежить від синтаксичного аналізу HTML. Він потрібний для того, щоб показати деякі динамічний вміст або змонтувати react/angular компонент на сторінці.
  • JavaScript - file2.js~460B - невеликий, незалежний файл javascript, який взаємодіє з dom.
  • JavaScript - file3.js ~ 1.5 MB - це вторинний файл js і залежить від file1.js, щоб виконати деякий, що має нижчий пріоритет код. Цей код не потрібен одразу для рендерингу сторінки та взаємодії з користувачем; він показує іконки соціальних мереж, коментарі, онлайн-допомога, запуск деяких завдань аналітики і т.д.
Тепер настав час проаналізувати різні підходи

Підхід-1 [скрипти у розділі head]

У першому випадку ми завантажимо всі теги scripts до розділу head нашого HTML. Нижче наведено скріншот аналізу мережевої вкладки chrome сторінки, готової для взаємодії з користувачем.

Плюси:

Послідовність виконання коду різних JS-файлів буде збережена в порядку, в якому файли були включені в HTML. У поточному прикладі, навіть якщо file2 та file3 були завантажені до file1, порядок виконання буде правильним.

Мінуси:

У цьому сценарії синтаксичний аналіз HTML буде призупинено доти, доки всі 3 скрипти в розділі head не будуть завантажені, проаналізовані та виконані. Порожній білий екран буде показаний користувачеві, навіть якщо HTML-файл вже завантажено [але не проаналізовано]. Це, безумовно, не є добре для юзабіліті.

Жоден з перерахованих вище скриптів не зможе отримати доступ / маніпулювати HTML-сторінкою, так як DOM ще не готовий. Одним із можливих рішень для обробки цієї проблеми є прослуховування події DOMContentLoaded, а потім виконання коду після цього. DOMContentLoadedПодія спрацьовує, коли вихідний HTML-документ був повністю завантажений і проаналізований, не чекаючи завершення завантаження таблиць стилів, зображень.

Підхід-2 [скрипти наприкінці]

Щоб подолати 2 проблеми, з якими ми стикаємося в першому підході, завантажимо всі 3 скрипти в нижній частині тега body.

Плюси: HTML аналізується перед завантаженням скриптів, так що користувач матиме можливість бачити фактичний зміст одразу замість того, щоб чекати скриптів.

Оскільки всі скрипти виконуються після розбору HTML, всі вони можуть отримати доступ до DOM для будь-яких маніпуляцій. Послідовність виконання скриптів зберігається.

Мінуси:

Немає приросту продуктивності як такого.

Підхід-3 [використання атрибута Async]

HTML5 представив async атрибут script, який допомагає в завантаженні відповідних файлів скрипта паралельно до іншого потоку, не впливаючи на синтаксичний аналіз HTML.

Тим не менш, відповідний сценарій буде проаналізовано і виконано, як тільки він завершить завантаження, незалежно від того, чи завершено синтаксичний аналіз HTML, і буде мати посилання на елемент DOM до цієї конкретної точки.

Тут можна чітко побачити, що file2.js був завантажений до HTML файлу. Однак, у той час як браузер завантажує file2, він не призупинив синтаксичний аналіз HTML і через це, до часу його виконання він мав посилання на заповнювач html, щоб ввести динамічний вміст.

Плюси:Оскільки скрипти завантажуються в іншому потоці, синтаксичний аналіз HTML не буде припинено, і користувач зможе бачити безпосередній контент замість білого екрана. Основний приріст продуктивності, тобто DOMContentLoaded час зменшився з 47.68 секунд до всього 21.12 секунд і становить ~ 55% приросту.

Мінуси:

Послідовність виконання JS не зберігається. Він виконується у відповідному порядку завантаження, а не увімкненої послідовності скриптів усередині HTML. Підтримка браузера - не підтримується на старих браузерах, тобто IE 9 і нижче.

Що станеться, якщо JS завантажується до того, як DOM елемент буде доступний? Буде викинуто помилку.

Примітка: розміщення скриптів з атрибутом async у нижній частині розділу body буде марним та еквівалентним підходу-2.

Підхід-4 [використання атрибута Defer]

Defer атрибут змусить скрипт виконатися лише після того, як парсинг HTML був завершений. Один дуже важливий момент, який слід враховувати тут, полягає в тому, що Chrome ще не підтримує відстрочку і не впливає на тривалість DOMContentLoaded. Проте він виконує скрипти наприкінці синтаксичного аналізу HTML.

Плюси:

Послідовність імпорту скриптів зберігається. Отже, file3.js виконується лише після завершення завантаження та виконання file1, навіть якщо file3 було завантажено раніше.

Підтримка браузерів - він має кращу підтримку браузерів у порівнянні з атрибутом asynс, тобто частково підтримується в IE v6-9

Скрипти можуть отримати доступ до DOM, тому що він виконується тільки після аналізу повного HTML.

Мінуси:

Спочатку я думав, що відстрочка буде кращим вибором, ніж асинхронність, але пізніше виявив, що Chrome ще не підтримує його [версія 71.0.3578.98] і не впливає на тривалість DOMContentLoaded.

Тим не менш, він працює так, як очікувалося, Firefox зі значним поліпшенням продуктивності.

Висновки

Переважно розміщувати теги скриптів у розділі head з атрибутом async для сторонніх бібліотек, які залежать від Google Analytics, Google reCAPTCHA або чогось іншого, що не вимагає DOM-доступу, оскільки відповідні скрипти завантажуються паралельно, але виконуються негайно.

Використовуйте defer для всіх інших скриптів, завантажених у розділі head, оскільки вони також завантажуватимуться паралельно, але будуть виконуватися тільки після завершення синтаксичного аналізу HTML і DOM готовий до доступу/маніпуляції.

Ви також можете використовувати поєднання DOMContentLoaded listener всередині асинхронних скриптів для виконання функціональності пізніше. Будь ласка, залиште свої думки та висновки у коментарях, і я буду радий обговорити їх з вами.


Автор цього матеріалу – я – Пахолков Юрій. Я надаю послуги з написання програм мовами Java, C++, C# (а також консультую з них) та створення сайтів. Працюю з сайтами на CMS OpenCart, WordPress, ModX та самописними. Крім цього, працюю безпосередньо з JavaScript, PHP, CSS, HTML - тобто можу доопрацювати ваш сайт або допомогти з веб-програмуванням.

IPad