Как работают браузеры: понятное техническое объяснение
Это простая техническая статьи, из которой вы поймете детали и сформируете интуитивное понимание работы браузеров.
Это адаптированный перевод материала How Browsers Work, подготовленный специально для читателей Tproger.
Зачем это нужно?
Эту статью написали для разработчиков и всех, кто пользуется браузерами каждый день, но никогда не разбирался в том, как они устроены изнутри.
Автор посчитал, что большинство существующих гайдов либо слишком технические и детализированные, либо, наоборот, поверхностные. Поэтому он решил выбрать другой подход.
Руководство построено на небольших примерах, чтобы понять технические детали и сформировать интуитивное понимание работы браузеров.
Чтобы материал оставался кратким и по существу, автор намеренно опустил многие критические детали: разные версии HTTP-протокола, SSL, TLS, нюансы работы DNS и многое другое.
Браузеры работают с URL
Вы можете ввести в адресную строку буквально что угодно. Но под капотом браузеры работают с URL:
- Случайный текст вроде «pizza» будет преобразован в поисковый URL типа https://google.com/search?q=pizza
- Доменное имя вроде example.com будет нормализовано в полный URL: https://example.com
Чтобы увидеть, как это работает на практике, попробуйте ввести «pizza» или «example.com» в адресную строку браузера.
Превращение URL в HTTP-запрос
Когда браузер знает точный URL, который нужно посетить, он может отправить запрос на сервер, чтобы получить ресурс и отобразить его. Браузеры общаются с серверами по протоколу HTTP.
Чтобы понять, как URL переводится в формат HTTP-запроса, рассмотрим пример с полным URL вроде example.com.
HTTP-запросы содержат заголовки в таком формате:
Один из заголовков — это заголовок Host. Он используется для идентификации сервера, на который отправляется запрос: example.com.
Определение адреса сервера
Браузеры не могут отправлять запросы на имена вроде example.com.
Компьютеры общаются с IP-адресами, поэтому браузер сначала обращается к системе DNS, чтобы преобразовать доменное имя в IP-адрес, прежде чем подключиться к серверу и отправить HTTP-запрос.
Например, если вы введёте в терминале команду для разрешения домена, DNS вернёт соответствующий IP-адрес:
Установка TCP-соединения
После того как DNS предоставил браузеру IP-адрес, всё ещё требуется надёжное соединение с сервером. TCP — это протокол, который устанавливает такое соединение до того, как будут отправлены любые HTTP-данные.
TCP устанавливает соединение с помощью трёхэтапного согласия, которое подтверждает, что обе стороны готовы отправлять и получать данные:
- SYN: клиент отправляет свой порядковый номер (seq=1000), чтобы открыть соединение
- SYN-ACK: сервер подтверждает пакет, добавляя свой порядковый номер (seq=5000) и подтверждая номер клиента, увеличивая его на 1 (ack=1001)
- ACK: клиент подтверждает номер сервера, увеличивая его на 1 (ack=5001), и соединение готово
Эти номера показывают, как клиент и сервер отслеживают диалог. Они считают байты, поэтому обе стороны согласны с тем, где начинается поток данных и что должно произойти дальше. Если какие-то данные не приходят, отправитель видит разрыв и повторно передаёт недостающие байты. Именно так TCP поддерживает порядок данных и надёжность после установки соединения.
Когда вы начинаете отправлять пакеты и пытаетесь нарушить работу сети, вы можете увидеть, как TCP справляется с потерями данных и восстанавливает передачу.
HTTP-запросы и ответы
После установки TCP-соединения браузер может отправить HTTP-запрос на сервер.
Представьте, что вы наблюдаете за тем, как HTTP-запрос путешествует к серверу, а HTTP-ответ возвращается в браузер:
БРАУЗЕР (КЛИЕНТ)
СЕРВЕР
Когда приходит HTTP-ответ, браузер читает сырой HTTP-ответ и начинает рендеринг HTML-контента.
Парсинг HTML для построения DOM-дерева
После того как приходит HTTP-ответ, браузер отделяет заголовки от тела и направляет HTML-байты в парсер. Парсер превращает теги вроде <h1> в токены и строит DOM-дерево.
Посмотрите, как HTML-поток парсится в DOM-дерево:
DOM-дерево:
Парсинг происходит потоково и устойчив к ошибкам: браузер начинает строить узлы ещё до того, как документ полностью загружен, и вставляет недостающие теги, чтобы дерево оставалось валидным. Когда появляется тег <script>, парсинг может приостановиться, чтобы выполнить скрипт.
DOM-дерево затем объединяется с CSS, чтобы создать render tree (дерево рендеринга), которое используется для расчёта layout и отрисовки пикселей.
О важности DOM
DOM — это внутренняя модель документа в памяти браузера. Это общий контракт между HTML-парсером, движком CSS-селекторов и средой выполнения JavaScript. Изменения в DOM немедленно влияют на layout, стили и то, с чем пользователи могут взаимодействовать.
DOM обеспечивает всё: от выборки элементов до динамической стилизации и обработки событий. Попробуйте отредактировать JavaScript-код и посмотрите, как меняется DOM:
Редактируемый JavaScript:
Живой DOM:
Layout, Paint и Composite
После того как DOM и CSS готовы, браузер запускает конвейер рендеринга: Layout (reflow) для расчёта размеров и позиций, Paint для заполнения пикселей, затем Composite для сшивки слоёв на GPU.
Не каждое изменение запускает все этапы заново. Изменение цвета обычно требует только перерисовки (repaint), тогда как изменение размеров заставляет пересчитывать layout и paint.
Этапы рендеринга:
- Layout — пересчёт размеров и позиций
- Paint — заполнение пикселей в слои
- Composite — сшивка слоёв на GPU
Пример DOM:
Composite всегда смешивает слои в финальный кадр.
Именно поэтому страницы с большим количеством layout-операций ощущаются медленнее: больше работы нужно выполнить, прежде чем можно будет показать следующий кадр.
Вот и всё! Если вы разобрались со всеми примерами, у вас должна сформироваться чёткая ментальная модель работы браузеров.
Теперь вы понимаете путь от ввода URL в адресную строку до отображения пикселей на экране: разрешение DNS, установку TCP-соединения, отправку HTTP-запросов, парсинг HTML, построение DOM и конвейер рендеринга с этапами Layout, Paint и Composite.