Что делает браузер после получения HTML по HTTP

Что происходит, когда HTTP прислал HTML? Что браузер дальше делает c HTML с учетом того, что она валидная?

Теория по задаче

Контекст: от HTTP до HTML

После получения ответа по HTTP определяется, как интерпретировать тело ответа: важны статус, заголовки и прежде всего медиатип, например Content-Type: text/html.

Далее байтовый поток преобразуется в поток символов (Unicode-кодпоинтов) с учетом кодировки. Для HTML применяется механизм определения кодировки: учитываются BOM, параметр charset в Content-Type, а также метатеги вида meta charset="utf-8" в начале документа.

Если HTML валидный, это означает корректность разметки относительно правил, но сам конвейер обработки не меняется: браузер все равно выполняет декодирование, потоковый разбор, построение DOM, загрузку подресурсов и рендеринг. Валидность снижает вероятность «неожиданных» исправлений разметки парсером, но не отменяет его работу.

Упрощенная цепочка на этом этапе: HTTP bytes → decode/encoding sniffing → Unicode code points → HTML parsing

Даже при 'валидной' HTML (в смысле отсутствия синтаксических ошибок) этап кодировки остаётся критичным: один и тот же набор байтов при разной кодировке даёт разные символы, а значит — другой DOM и другую интерпретацию документа.

Парсинг HTML и построение DOM

HTML парсится потоково: по мере поступления символов запускается токенизация (превращение текста в токены), а затем построение дерева (добавление узлов в DOM). Итогом является объект Document и дерево узлов (элементов, текстовых узлов, комментариев и т. п.).

Парсер не «читает HTML как XML». Вместо этого применяется специализированный алгоритм с режимами вставки (insertion modes), которые зависят от контекста: одинаковый токен может обрабатываться по-разному в <head>, <body>, таблицах и т. п. Это сделано для совместимости с историческим Web и для предсказуемого результата на реальных страницах.

Даже при валидной разметке возможны технические остановки/возобновления парсинга. Например, выполнение некоторых скриптов может «вмешаться» в процесс (изменить DOM, вставить HTML), поэтому основной парсер обязан корректно синхронизировать построение дерева с выполнением JavaScript.

Упрощенная схема внутренностей: code points → tokenizer → tokens → tree construction → DOM

В представлении браузеров 'валидная HTML' не означает «простая»: даже идеально корректная разметка может приводить к паузам парсера из‑за синхронных 'script', а также к повторным перерасчётам отображения по мере загрузки CSS/JS и изменения DOM.

Подресурсы и блокировки парсинга/рендеринга

По мере разбора HTML обнаруживаются подресурсы: стили, скрипты, изображения, шрифты, iframe и т. п. Браузер старается запрашивать их как можно раньше, чтобы сократить общее время загрузки страницы.

Некоторые ресурсы и действия могут блокировать основной парсер или откладывать визуальный вывод:

  • Синхронные <script src="..."> без async/defer обычно приостанавливают разбор HTML до загрузки и выполнения, потому что скрипт может изменить документ и продолжать парсинг «вперед» небезопасно с точки зрения корректности результата.
  • Стили из <link rel="stylesheet" href="..."> обычно блокируют рендеринг (показ), чтобы не показывать пользователю «голую» страницу без CSS и не провоцировать резкие визуальные скачки.

Чтобы уменьшить простои, в современных браузерах существует «спекулятивный» механизм раннего обнаружения ресурсов (preload scanner). Он сканирует HTML разметку параллельно основному парсеру и пытается заранее поставить в очередь загрузку ресурсов, даже если основной парсер временно остановлен скриптом.

Ограничения такого подхода важны для понимания поведения:

  • Ресурсы, создаваемые только через JavaScript (например, const img = new Image(); img.src = "..."), не будут обнаружены заранее, пока скрипт не выполнится.
  • Ресурсы, упомянутые только внутри CSS (например, background-image: url(...)), не извлекаются из HTML-сканирования и появятся в сети позже — после загрузки и разбора CSS.

Мини-таблица типичных эффектов:

Ситуация в документеЧто тормозитсяПричина
<script src="app.js"> без async/deferПарсинг HTML и часто первый показСкрипт может менять DOM и поток разбора.
<link rel="stylesheet" href="styles.css">Рендеринг (визуальный показ)Избежание отображения без стилей и скачков оформления.
Основной парсер «стоит» на скриптеСеть продолжает работу через раннее сканированиеРанние запросы подресурсов сокращают общий критический путь.

Рендеринг: от DOM/CSSOM к пикселям

После (или параллельно) построения DOM загружаются и разбираются CSS-ресурсы, формируя CSSOM — внутреннюю модель правил стилей. Затем выполняется сопоставление стилей: для каждого узла DOM вычисляются итоговые значения CSS-свойств (cascade → computed values).

Далее строится render tree (дерево рендеринга): оно похоже на DOM, но учитывает визуальные особенности (например, элементы с display: none не попадают в render tree). На основе render tree выполняются:

  • Layout (reflow): вычисление размеров и позиций боксов.
  • Paint: превращение боксов в команды рисования и затем в пиксели.
  • Compositing: сборка слоев (например, при transform, opacity, фиксированных элементах) в финальную картинку кадра.

Важные практические последствия:

  • Любые изменения DOM или CSS (в том числе из JavaScript) могут вызвать перерасчет стилей и layout, что дорого по времени и влияет на плавность.
  • Длительное выполнение JavaScript на главном потоке может задерживать и обработку событий, и рендеринг, даже если сеть уже все скачала.

Упрощенная цепочка для запоминания: HTML → DOM + CSS → CSSOMstyle calculationrender treelayoutpaintcomposite

Итого: после получения HTML браузер декодирует байты в символы, потоково парсит HTML в DOM, параллельно инициирует загрузку подресурсов и может приостанавливать парсинг/показ из‑за скриптов и стилей, затем строит CSSOM и render tree и выполняет layout/paint/compositing для вывода пикселей на экран.