Браузер. Основные принципы работы.

Браузер. Основные принципы работы.

Alex Bankay @BBankay

Sup?


Ну что, устраивайся поудобнее. Речь пойдет про...


Основное предназначение браузера – отображать веб-ресурсы. Для этого браузер отправляет запросы на сервер, а сервер, в свою очередь, отправляет браузеру ответы.


Под ресурсами в основном подразумеваются HTML-документы, однако это может быть PDF-файл, картинка, аудио, видео или иное содержание. 


Структура браузера с "высоты птичьего полета"


  1. Пользовательский интерфейс – адресная строка, кнопки "Назад" и "Вперед", меню закладок и т. д. К нему относятся все элементы, кроме окна, в котором отображается запрашиваемая страница.
  2. Движок браузера – управляет взаимодействием интерфейса и модуля отображения.
  3. Модуль отображения – отвечает за вывод запрошенного веб-ресурса на экран. 
  4. Сетевые компоненты – предназначены для выполнения сетевых вызовов, таких как HTTP-запросы. 
  5. UI Backend – используется для отрисовки основных виджетов, таких как окна и поля со списками. Этот модуль всегда применяет методы пользовательского интерфейса конкретной операционной системы.
  6. Интерпретатор JavaScript – используется для синтаксического анализа и выполнения кода JavaScript.
  7. Хранилище данных – необходимо для сохраняемости процессов. Браузер сохраняет на жесткий диск данные различных типов, например файлы cookie. 

Critical Rendering Path

Набор шагов, необходимых для первого отображения страницы, называется «Критический путь рендеринга». Существует 6 этапов CRP:

  • Построение DOM-дерева,
  • Построение CSSOM-дерева,
  • Запуск JavaScript,
  • Создание Render-дерева,
  • Генерация раскладки,
  • Отрисовка.


Построение DOM дерева

HTML документ подвергается синтаксическому анализу. Результатом синтаксического анализа, как правило, является дерево узлов, представляющих структуру документа - DOM: разобранный html код в виде дерева объектов.


DOM (Объектная модель документа) служит программным интерфейсом. Это значит, что вы можете изменять HTML документ посредством изменения DOM. Чаще всего мы пишем скрипты на Java Script, которые меняют DOM, а браузер, в ответ на эти изменения динамически меняет содержимое HTML документа.


HTML заметки

Документ не должен быть загружен полностью, чтобы начать отображаться на экране. Поэтому часть html может быть на экране, в то время как остальная часть еще перемещается по сети.

Мы можем делать ошибки при написании HTML кода и браузер никогда не будет на них ругаться. Все дело в том, что очень большая часть алгоритма парсинга и анализа "исправляет" HTML ошибки за нас.

Построение CSSOM-дерева

CSSOM (объектная модель CSS) — это объект, представляющий стили, связанные с DOM. Он выглядит так же как DOM, но с соответствующими стилями для каждого узла. Не имеет значения были ли стили объявлены явно или наследуются.


CSS считается «блокирующим обработку ресурсом». Это значит, что Render-дерево (см. ниже) не может быть построено без полного первоначального разбора CSS.

В отличии от HTML, CSS не может быть использован по частям в силу своей каскадной природы. Стили, описанные в документе ниже, могут переопределять и изменять стили, определённые ранее. Так что если мы начнём использовать CSS-стили до того, как будет разобрана таблица стилей, мы можем столкнуться с ситуацией, когда стили будут применяться неверно. Это означает, что для перехода к следующему шагу, необходимо полностью разобрать CSS.

CSS-файлы блокируют рендер только если они применяются. 
<link rel="stylesheet">
 может принимать медиа-атрибут, в котором мы можем указать любое медиавыражение, к которому будут относиться вложенные внутрь стили. Если, например, мы имеем таблицу стилей с медиа-атрибутом orientation:landscape, а мы просматриваем страницу в портретном режиме, то этот ресурс не будет считаться блокирующим обработку.

CSS также может являться «блокирующим скрипты», потому что JavaScript-файлы должны дождаться построения CSSOM, прежде чем начать исполняться.


Запуск JavaScript

JavaScript является блокирующим ресурсом для парсера. Это означает, что JavaScript блокирует разбор самого HTML-документа.

Когда парсер доходит до тега <script> (не важно внутренний он или внешний), он останавливается, забирает файл (если он внешний) и запускает его. Вот почему, если мы имеем JavaScript-файл, который ссылается на элементы документа, мы обязательно должны поместить его после их появления - например в самом конце, перед тегом </body>. Но будет проблема, если HTML большой, а интернет соединение на клиенте медленное. Ведь пока дело дойдет до тега <script> пройдет много времени.

Решение: атрибут defer или async. Они оба позволяют не блокировать отрисовку страницы. Так что пользователь может просмотреть содержимое страницы и ознакомиться с ней сразу же.

Подробнее на learn.javascript.ru

Создание Render-дерева

Render-дерево — это совокупность DOM и CSSOM. Это дерево, которое даёт представление о том, что в конечном итоге будет отображено на странице. Это означает, что оно захватывает только видимый контент и не включает, например, элементы, которые были скрыты с помощью CSS-правила display: none.

На примерах DOM и CSSOM, представленных выше, будет построено такое Render-дерево:


Генерация раскладки (layout)

Раскладка — это то, что определяет размер видимой области документа (viewport), а также рассчитывает геометрические данные для будущих объектов отображения.

Размер вьюпорта определяется метатэгом, находящемся в <head> документа

Если пользователь посещает веб-страницу с устройства, ширина которого, например 1000 пикселей, то размеры будут опираться на это значение. Половина видимой области будет равна 500 пикселей, 10 процентов — 100 пикселей, и так далее.

В HTML используется поточная модель раскладки, то есть в большинстве случаев геометрические данные можно рассчитать за один проход. Элементы, встречающиеся в потоке позднее, не влияют на геометрию уже обработанных элементов, поэтому компоновку можно выполнять слева направо и сверху вниз.

Любой объект отображения может при необходимости вызвать метод layout или reflow для своих дочерних элементов.

Система "грязных битов"

Чтобы не выполнять заново раскладку при каждом изменении, браузеры используют так называемую систему "грязных битов". Измененный объект отображения и его дочерние элементы помечаются как "грязные", то есть требующие перераскладки.

Используется два флага: dirty и children are dirty. Флаг children are dirty означает, что перекомпоновка требуется не самому объекту отображения, а одному или нескольким из его дочерних объектов.

Глобальная и инкрементная раскладка

Если раскладка выполняется для всего дерева отображения, она называется глобальной. Ее могут вызывать перечисленные ниже события.

  1. Глобальное изменение стиля, который используется во всех объектах отображения, например изменение шрифта.
  2. Изменение размеров экрана.

При инкрементной раскладке изменяются только "грязные" объекты отображения. Она выполняется асинхронно и начинается при обнаружении "грязных" объектов отображения. Пример: после получения содержания из сети и его добавления в дерево DOM в дереве отображения появляется новый объект.

Оптимизация

Если раскладка вызвана событием resize или изменением положения (но не размера) объекта отображения, размеры объекта извлекаются из кэша и не рассчитываются заново.

Если меняется только часть дерева, перераскладка всего дерева не выполняется. Это происходит, если изменение носит локальный характер и не влияет на окружающие объекты, например при вводе текста в текстовые поля (в остальных случаях ввод каждого символа вызывает перераскладку всего дерева).


Этап отрисовки

На этапе отрисовки для каждого объекта отображения по очереди вызывается метод paint и их содержание выводится на экран.

Глобальная и инкрементная отрисовка

При глобальной отрисовке все дерево отрисовывается целиком, а при инкрементной – только отдельные объекты отображения, не влияющие на остальные части дерева. Измененный объект отображения помечает свой прямоугольник как недействительный. Операционная система расценивает его как "грязную" область и вызывает событие paint. Области при этом объединяются, чтобы отрисовку можно было выполнить сразу для всех.

Динамические изменения

При наступлении изменений браузеры стараются не выполнять лишних операций. Например, при изменении цвета одного элемента остальные не отрисовываются заново. При изменении положения элемента выполняется повторная компоновка и отрисовка его самого, его дочерних элементов и, возможно, других объектов того же уровня. При добавлении узла DOM выполняется его повторная компоновка и отрисовка. Серьезные изменения, такие как увеличение размера шрифта элемента html, ведут к очистке кэша и повторной компоновке и отрисовке целого дерева.


Собираем всё вместе

Чтобы увидеть как происходит критический путь рендеринга, мы можем воспользоваться инструментами разработчика. В Chrome это можно сделать во вкладке «Performance». Сохраните код ниже в файле index.html, а также создайте в той же папке style.css и main.js.

<html>
  <head>
    <title>Understanding the Critical Rendering Path</title>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <h1>Understanding the Critical Rendering Path</h1>
    <script src="main.js"></script>
  </body>
</html>


Если мы посмотрим в Event Log для этой страницы, то увидим следующее:

  1. Send Request — GET-запрос, отправленный для index.html;
  2. Parse HTML and Send Request — начать разбор HTML и построение DOM. Отправить GET запрос для style.css и main.js;
  3. Parse Stylesheet — CSSOM, созданный для style.css;
  4. Evaluate Script — вычислить (выполнить) main.js;
  5. Layout — генерация раскладки, основанной на значении метатега viewport;
  6. Paint — отрисовка пикселей в документе.


Ссылки

Принципы работы современных браузеров

Понимание критического пути рендеринга

Critical rendering path

Скрипты: async и defer

Что такое объектная модель документа


Основной телеграм канал: @frontbase
Обратная всязь: @BBankay


Have fun, mate.

Report Page