\n Page\n\n```\n\n**При встрече с `\n \n\n\n \n

Контент

\n

Невидим до загрузки скрипта

\n\n```\n\n**Последовательность:**\n1. Браузер начинает парсить HTML (0мс)\n2. Встречает `\n \n\n```\n\n**Что происходит с async:**\n1. Парсинг продолжается (не блокируется)\n2. Браузер загружает скрипт в фоне\n3. Когда скрипт готов - выполняется (может прерватьпарсинг на момент выполнения)\n4. Парсинг продолжается\n\n**Проблема:** порядок выполнения не гарантирован\n\n#### Оптимизация 2: Атрибут `defer`\n\n```html\n\n \n \n\n```\n\n**Что происходит с defer:**\n1. Парсинг продолжается (не блокируется)\n2. Браузер загружает скрипт в фоне\n3. Парсинг завершается (весь HTML спарсен)\n4. Скрипт выполняется в порядке появления\n5. DOM ready (DOMContentLoaded)\n\n**defer - обычно лучший выбор для большинства скриптов.**\n\n#### Оптимизация 3: Инлайн скрипт в конце body\n\n```html\n\n

Content

\n

Виден браузером перед выполнением скрипта

\n \n \n\n```\n\n### Практический пример: Оптимальная структура\n\n```html\n\n\n\n \n \n \n \n \n \n \n \n \n \n \n\n\n

Content

\n \n \n \n \n \n \n \n\n\n```\n\n### Сравнение эффектов\n\n| Тег | Блокирует парсинг | Блокирует рендеринг | Асинхронность |\n|-----|------------------|-------------------|---------------|\n| `` | НЕТ | ДА | Загрузка async, применение sync |\n| `` | НЕТ | НЕТ | Полностью async |\n| `
← Назад к вопросам

Что происходит при встрече с тегами link, img, script при формировании DOM-дерева?

2.0 Middle🔥 201 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что происходит при встрече тегов link, img, script при формировании DOM-дерева

Когда браузер парсит HTML и встречает теги <link>, <img>, <script>, он выполняет различные действия в зависимости от типа тега. Это критично для понимания производительности и оптимизации загрузки страницы.

Обзор процесса парсинга

Серверная доставка HTML
  |
  v
Браузер начинает парсить HTML (streaming)
  |
  v
Встреча с <head> элементами (link, script, meta)
  |
  v
Встреча с <body> элементами (div, p, img, script)
  |
  v
Построение DOM дерева

Встреча с тегом <link>

Что происходит

<head>
  <link rel="stylesheet" href="styles.css">
  <link rel="preconnect" href="//fonts.googleapis.com">
</head>

При встрече с <link>:

  1. Парсер НЕ блокируется - продолжает парсить HTML дальше
  2. Браузер начинает загрузку ресурса асинхронно - запрашивает CSS файл с сервера
  3. DOM элемент добавляется в дерево сразу - <link> попадает в DOM
  4. CSS парсится и применяется - когда ресурс загружается

Важно: CSS не блокирует парсинг HTML, но блокирует рендеринг.

Двойная ответственность CSS:
1. Загрузка <- асинхронная (парсинг продолжается)
2. Применение <- блокирует рендеринг (рендеринг ждет)

Пример: Эффект на производительность

<head>
  <!-- Внешний CSS - загружается асинхронно, но блокирует рендеринг -->
  <link rel="stylesheet" href="https://cdn.example.com/styles.css">
</head>
<body>
  <h1>Hello World</h1>
  <!-- Браузер не будет рендерить страницу, пока CSS не загружен -->
</body>

Последовательность:

  1. Парсер создает DOM элементы (h1 добавляется в дерево)
  2. Браузер ждет загрузки CSS
  3. CSS применяется к элементам
  4. Рендеринг начинается

Если CSS на медленном сервере - белый экран до 5-10 секунд!

Оптимизация:

<!-- dns-prefetch для сервера CSS -->
<link rel="dns-prefetch" href="https://cdn.example.com">

<!-- preload для критичного CSS -->
<link rel="preload" href="/critical.css" as="style">

<!-- async загрузка некритичного CSS -->
<link rel="stylesheet" href="/non-critical.css" media="print">

Встреча с тегом <img>

Что происходит

<body>
  <img src="image.jpg" alt="Example">
  <p>Next content</p>
</body>

При встрече с <img>:

  1. Парсер НЕ блокируется - продолжает парсить HTML дальше
  2. <img> добавляется в DOM сразу - элемент в дереве
  3. Браузер начинает загрузку изображения асинхронно - запрашивает картинку
  4. Парсинг продолжается - не ждем изображение
  5. Рендеринг может начаться - даже если изображение не загружено
  6. Когда изображение загружается - браузер перерисовывает область

Важно: <img> НЕ блокирует ничего - это самый "безопасный" из трех тегов.

Пример: Множество изображений

<body>
  <img src="image1.jpg">
  <img src="image2.jpg">
  <img src="image3.jpg">
  <p>Text below images</p>
</body>

Что происходит:

  • Все три изображения добавляются в DOM (0мс)
  • Браузер загружает их параллельно (может быть 6+ одновременных соединений)
  • Текст рендерится, даже если изображения загружаются
  • Когда каждое изображение загружается, браузер перерисовывает его область

Проблема: Layout Shift

<!-- ПЛОХО - без width/height -->
<img src="image.jpg">
<!-- Браузер не знает размер - рендерит как 0x0 -->
<!-- Когда изображение загружается - layout shift! Весь контент сдвигается -->

<!-- ХОРОШО - с width/height -->
<img src="image.jpg" width="800" height="600">
<!-- Браузер резервирует место - no layout shift -->

Оптимизация:

<!-- lazy loading -->
<img src="image.jpg" loading="lazy">

<!-- Резервирование места -->
<img src="image.jpg" width="800" height="600">

<!-- Responsive изображения -->
<picture>
  <source srcset="image-mobile.jpg" media="(max-width: 768px)">
  <img src="image-desktop.jpg" alt="Example">
</picture>

Встреча с тегом <script>

Что происходит

<head>
  <script src="script.js"></script>
  <title>Page</title>
</head>

При встрече с <script> (по умолчанию):

  1. ПАРСЕР БЛОКИРУЕТСЯ - прекращает парсить HTML
  2. Браузер загружает JavaScript файл - синхронный запрос
  3. JavaScript выполняется - весь код запускается
  4. Только потом парсинг продолжается - возвращаемся к HTML
  5. Может быть доступ к DOM - но только к уже спарсеному

Это ОЧЕНЬ дорого в плане производительности!

Пример: Блокировка парсинга

<head>
  <script src="https://slow-server.com/script.js"></script>
  <!-- Ждем 5 секунд загрузки скрипта -->
</head>
<body>
  <!-- Парсинг здесь начнется только через 5+ секунд! -->
  <h1>Контент</h1>
  <p>Невидим до загрузки скрипта</p>
</body>

Последовательность:

  1. Браузер начинает парсить HTML (0мс)
  2. Встречает <script src="..."> (50мс)
  3. Парсинг ОСТАНАВЛИВАЕТСЯ (50мс)
  4. Браузер загружает скрипт (50мс - 5050мс)
  5. JavaScript выполняется (5050мс - 5100мс)
  6. Парсинг ВОЗОБНОВЛЯЕТСЯ (5100мс)
  7. Продолжает парсить body и создавать DOM
  8. Рендеринг начинается - но уже прошло 5+ секунд!

Это крайне плохо для пользовательского опыта.

Оптимизация 1: Атрибут async

<head>
  <script src="script.js" async></script>
  <!-- async не блокирует парсинг -->
</head>

Что происходит с async:

  1. Парсинг продолжается (не блокируется)
  2. Браузер загружает скрипт в фоне
  3. Когда скрипт готов - выполняется (может прерватьпарсинг на момент выполнения)
  4. Парсинг продолжается

Проблема: порядок выполнения не гарантирован

Оптимизация 2: Атрибут defer

<head>
  <script src="script.js" defer></script>
  <!-- defer загружает в фоне, выполняет после парсинга -->
</head>

Что происходит с defer:

  1. Парсинг продолжается (не блокируется)
  2. Браузер загружает скрипт в фоне
  3. Парсинг завершается (весь HTML спарсен)
  4. Скрипт выполняется в порядке появления
  5. DOM ready (DOMContentLoaded)

defer - обычно лучший выбор для большинства скриптов.

Оптимизация 3: Инлайн скрипт в конце body

<body>
  <h1>Content</h1>
  <p>Виден браузером перед выполнением скрипта</p>
  
  <script>
    // Инлайн скрипт - выполняется после парсинга
    document.querySelector('h1').style.color = 'red';
  </script>
</body>

Практический пример: Оптимальная структура

<!DOCTYPE html>
<html>
<head>
  <!-- Критичный CSS в head (блокирует рендеринг, но нужен) -->
  <link rel="stylesheet" href="/critical.css">
  
  <!-- DNS prefetch для внешних ресурсов -->
  <link rel="dns-prefetch" href="//api.example.com">
  
  <!-- Preconnect для критичных ресурсов -->
  <link rel="preconnect" href="//fonts.googleapis.com">
  
  <!-- Defer скрипты (не блокируют) -->
  <script src="app.js" defer></script>
</head>
<body>
  <h1>Content</h1>
  <img src="hero.jpg" width="1200" height="600" loading="lazy">
  
  <!-- Некритичный CSS в конце (не блокирует рендеринг) -->
  <link rel="stylesheet" href="/non-critical.css">
  
  <!-- Аналитика с async (не критична) -->
  <script src="analytics.js" async></script>
</body>
</html>

Сравнение эффектов

ТегБлокирует парсингБлокирует рендерингАсинхронность
<link rel="stylesheet">НЕТДАЗагрузка async, применение sync
<img>НЕТНЕТПолностью async
<script>ДАДАПо умолчанию sync
<script async>НЕТ(да, во время выполнения)Async
<script defer>НЕТ(да, перед DOMContentLoaded)Async загрузка

Ключевые метрики

FCP (First Contentful Paint) - когда первый контент рендерится

  • Зависит от CSS (может быть заблокирована)
  • Зависит от блокирующих скриптов

LCP (Largest Contentful Paint) - когда загружается основной контент

  • Часто это изображение или блок текста
  • Оптимизируй с width/height и lazy loading

CLS (Cumulative Layout Shift) - неожиданные сдвиги

  • Избегай без указания размеров изображений
  • Избегай динамического контента во время рендеринга

Итог

При формировании DOM-дерева:

  • <link> - не блокирует парсинг, но блокирует рендеринг. Разместить в <head>.
  • <img> - полностью асинхронный, не блокирует ничего. Всегда указывай размеры.
  • <script> - блокирует парсинг по умолчанию. Используй async или defer для оптимизации.

Для быстрой загрузки:

  1. Используй defer для основных скриптов
  2. Используй async для аналитики и сторонних сервисов
  3. Указывай ширину/высоту для изображений
  4. Используй lazy loading для офф-скрин изображений
  5. Минимизируй блокирующий CSS
Что происходит при встрече с тегами link, img, script при формировании DOM-дерева? | PrepBro