Скрипти в head
1. Як браузер завантажує сторінку
Коли браузер отримує HTML-документ, він виконує такі кроки:
- Парсить HTML порядково зверху вниз.
- Коли зустрічає тег
<link>(CSS), зупиняється і завантажує стиль, тому що стилі впливають на відображення. - Коли зустрічає тег
<script>, зупиняє парсинг, щоб виконати JS.
Чому? Тому що скрипт може змінити сам DOM або навіть видалити елементи, які йдуть далі в HTML (
document.write,innerHTMLтощо). Тому браузер зобов'язаний дочекатися виконання JS, перш ніж продовжити розбір.
2. Що відбувається, якщо script у head
javascript
<head>
<script src="main.js"></script>
</head>
<body>
<h1>Привіт!</h1>
</body>По кроках:
- Браузер починає читати HTML.
- Доходить до
<script src="main.js">. - Зупиняє парсинг HTML.
- Чекає, поки
main.jsзавантажиться по мережі (може зайняти сотні мілісекунд). - Виконує скрипт.
- Тільки потім продовжує парсити решту сторінки.
Увесь цей час:
- DOM ще не створено,
- користувач не бачить контенту,
- метрики FCP / LCP страждають.
3. Проблеми, які це спричиняє
| Проблема | Що відбувається |
|---|---|
| Блокується HTML-парсер | Сторінка не будується, поки не завантажиться JS |
| Довга "біла сторінка" | Користувач бачить порожнечу |
| Повільні мережі → гірший UX | Особливо на 3G/4G |
| Погіршення Core Web Vitals | LCP, FCP, TTI, TBT - зростають |
| Скрипти заважають критичним CSS | Критичні стилі не застосовуються вчасно |
4. Як уникнути блокування
Спосіб 1. defer
javascript
<script src="main.js" defer></script>Що робить:
- Скрипт завантажується паралельно з HTML,
- але виконується лише після повного парсингу DOM (перед
DOMContentLoaded).
Без блокування. Гарантований порядок виконання (по черзі). Ідеально для більшості випадків.
Спосіб 2. async
javascript
<script src="analytics.js" async></script>Що робить:
- Скрипт завантажується асинхронно (у фоні),
- і виконується одразу після завантаження, не чекаючи інших.
Використовується для незалежних скриптів (аналітика, реклама, пікселі). Порядок виконання не гарантується.
Спосіб 3. Перенесення скриптів у кінець body
javascript
<body>
...
<script src="main.js"></script>
</body>До завантаження JS:
- HTML повністю розпарсено,
- користувач уже бачить контент,
- JS виконується останнім кроком.
Це "старий", але робочий спосіб. У сучасному HTML його замінив <script defer>.
5. Як діяти в продакшені
| Тип скрипта | Де і як підключати |
|---|---|
| Основна логіка (UI, SPA) | <script src="main.js" defer> |
| Аналітика, реклама | <script src="ga.js" async> |
| Inline-ініціалізація | <script> усередині <head> (маленька ініціалізація) |
| Старі бібліотеки | Краще перенести в кінець <body> |
6. Вплив на метрики
| Метрика | Що погіршується при скриптах у head |
|---|---|
| FCP (First Contentful Paint) | Довше показується перший контент |
| LCP (Largest Contentful Paint) | Основний елемент відображається пізніше |
| TTI (Time to Interactive) | JS блокує основний потік |
| TBT (Total Blocking Time) | Зростає через важкі синхронні скрипти |
7. Ілюстрація (словами)
javascript
HTML: <head> -> <script> -> <body>
↓ завантаження
[======= JS завантажується =======]
↓ виконання
[======= JS виконується =======]
↓ тільки потім DOM будуєтьсяПри defer завантаження йде паралельно, а виконання - наприкінці:
javascript
HTML і JS завантажуються разом → DOM побудовано → JS виконуєтьсяКороткий підсумок
| Сценарій | Що робить | Наслідок |
|---|---|---|
<script> у head без атрибутів | Блокує парсинг | Повільно |
<script defer> | Завантажує паралельно, виконує після DOM | Оптимально |
<script async> | Завантажує і виконує незалежно | Лише для незалежних скриптів |
<script> унизу body | Чекає кінця HTML | Без блокування |
Коротка відповідь
Для співбесідиPremium
Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.