Text javascript async src завантажене. Асинхронна завантаження JavaScript - прискорюємо завантаження сторінок. Додавання атрибутів defer або async в WordPress
29.06.2020
Вітаю, друзі! Чи знаєте Ви, що завантаження JavaScript є одним з найбільш вузьких місць в продуктивності сайту? Сьогодні моє основне завдання - пояснити що таке скрипта і яким чином вона впливає на швидкодію і продуктивність сайту.
Браузер, що завантажує тег script, зупиняє рендеринг сторінки до тих пір, поки не завантажиться і не виповниться скрипт. Сторінка заблокована і браузер пару секунд не відповідає на дії користувача. Час затримки залежить від декількох факторів:
конфігурації,
швидкості інтернет-з'єднання,
розміру файлу і інших ...
З цієї причини аналізатор швидкості завантаження сайту Google PageSpeed \u200b\u200bInsights рекомендує видалити з верхньої частини сторінки код JavaScript, який блокує її відображення. Доброю практикою є розміщення скриптів в нижній частині сайту, наприклад, перед закриває тегом
або настройка асинхронної завантаження.
Якщо код скрипта впливає на відображення верхньої частини сайту - не виносьте його в окремий файл, а вбудовуйте безпосередньо в HTML.
JS може змінити вміст сайту і навіть перенаправляти на інший URL-адресу. У такому випадку підключення скрипта в кінці документа призведе до ефекту «посмикування» сторінки, довантажуючи нові або змінюючи існуючі елементи у верхній частині.
Застосування атрибутів async і defer для тега script
Давайте розберемося, що з себе представляє асинхронна і відкладена робота JavaScript і яка принципова різниця між атрибутами async і defer. Але спочатку розглянемо послідовність обробки документа при звичайному підключенні тега script.
< src \u003d "example.js"\u003e
>
У наочному прикладі я буду використовувати такі умовні позначення:
- обробка сторінки - завантаження скрипта - виконання скрипта
Таким чином послідовність обробки відбувається за такою схемою:
Розбір HTML-коду переривається на час завантаження і виконання скрипта, після чого продовжується. Відображення веб-сторінки відбувається із затримкою.
Атрибут defer
Атрибут defer дозволяє браузеру почати завантаження js-файлів паралельно, не зупиняючи подальшу обробку сторінки. Їх виконання відбувається після повного розбору об'єктної модель документа (від англ. Document Object Model, скорочено DOM), при цьому браузер гарантує послідовність на основі порядку підключення файлів.
< defer src \u003d "example.js"\u003e
>
Атрибут async
Підтримка атрибута async з'явилася в HTML5, він дозволяє браузеру завантажувати js-файли паралельно і виконувати відразу після завантаження, не чекаючи обробки решти сторінки.
< async src \u003d "example.js"\u003e
>
Схема послідовності обробки:
Це асинхронна завантаження. Атрибут рекомендується застосовувати для таких скриптів, які не роблять значного впливу на відображення документа. До них відносяться лічильники збору статистики (Google Analytics, Яндекс Метрика), коди рекламних мереж (Рекламна мережа Яндекса, Google AdSense), кнопки соціальних мереж і так далі.
Швидкість завантаження сайту - один з чинників ранжирування в Google.
Асинхронне підключення JavaScript знижує час завантаження сторінок за рахунок відсутності затримки. Поряд з цим я рекомендую стискати і об'єднувати js-файли в один, наприклад, за допомогою бібліотеки. Користувачам подобаються швидкі сайти 😎
Async і Defer - стратегії завантаження JavaScript
JavaScript є невід'ємною частиною будь-якого сучасного веб-додатки, і стратегії, які ми вирішуємо використовувати для завантаження, безпосередньо впливають на продуктивність роботи цього самого додатка. У даній статті ми спробуємо зрозуміти важливі відмінності між кожним підходом, плюси і мінуси поряд з наслідками продуктивності і способи оптимізації по взаємодії зі сторінкою і часу завантаження.
Для демонстрації я створю веб-сайт, що складається з наступних зовнішніх залежностей. Зверніть особливу увагу на відповідні розміри файлів, так як час завантаження файлів прямо пропорційно цьому.
HTML - сторінка ~ 1 МБ. Містить фактичну розмітку / вміст, щоб показати деякі динамічні вихідні дані з JavaScript.
Зображення - image1.png ~ 5 Мб
JavaScript - file1.JS ~ 3 МБ - це ядро \u200b\u200b(основний файл) 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 - тобто можу доопрацювати ваш сайт або допомогти з веб-програмуванням.
Підключаються скрипти (JavaScript) блокує завантаження HTML коду. Коли браузер (парсер) доходить до тега