Знаете ли вы как браузер обрабатывает index html расскажите про critical rendering path
Цель статьи, если я собираюсь создавать быстрые и надежные веб-сайты, мне нужно действительно понимать механику каждого шага, который браузер выполняет для отображения веб-страницы, чтобы каждый шаг был обдуман и оптимизирован во время разработки. Этот пост представляет собой краткое изложение моих знаний о процессе отображения страниц на довольно высоком уровне.
Много идей основано на фантастическом (и БЕСПЛАТНОН!) курсе по оптимизации производительности веб-сайта Website Performance Optimization Ilya Grigorik и Cameron Pittman на Udacity. Я очень рекомендую это посмотреть.
Также очень полезной оказалась статья Пола Айриша и Тали Гарсиэль How Browsers Work: Behind the scenes of modern web browsers. Хотя эта статья 2011 года, но многие основы работы браузеров остаются актуальными до сих пор.
И так, поехали. Процесс отображения страниц можно разбить на следующие основные этапы:
- Начало разбора HTML
- Получение внешних ресурсов
- Разбор CSS и создание CSSOM
- Выполнение JavaScript
- Объединение DOM и CSSOM, для построения дерево рендеринга
- Расчет макета и отрисовка результата
1. Начало разбора HTML
Когда браузер начинает получать данные HTML страницы по сети, он немедленно запускает свой синтаксический анализатор parser для преобразования HTML в объектную модель документа (DOM) Document Object Model (DOM).
2. Получение внешних ресурсов
Когда парсер встречает внешний ресурс, такой как файл CSS или JavaScript, он пытается, получить его. Синтаксический анализатор будет продолжать работу по мере загрузки файла CSS, но он заблокирует рендеринг до тех пор, пока файл не будет загружен и проанализирован (подробнее об этом чуть позже).
defer означает, что выполнение файла будет отложено до завершения синтаксического анализа документа. Если несколько файлов имеют атрибут defer, то они будут выполняться в том порядке, в котором они были обнаружены в HTML.
async означает, что файл будет выполнен, как только он загрузится, это может быть во время или после процесса синтаксического анализа, и поэтому порядок, в котором выполняются асинхронные сценарии, не может быть гарантирован.
Предварительная загрузка ресурсов
3. Разбор CSS и создание CSSOM
Возможно, вы слышали о DOM, но слышали ли вы о CSSOM (CSS Object Model) (объектной модели CSS)? До того, как я начал исследовать эту тему, я об этом ни чего не знал!
Чем CSSOM отличается от DOM, так это тем, что он не может быть построен постепенно, поскольку правила CSS могут перезаписывать друг друга в разных точках из-за specificity (порядка применения свойства). Вот почему загрузка CSS блокирует рендеринг, поскольку до тех пор, пока весь CSS не будет проанализирован и не будет построен CSSOM, браузер не может знать, где и как разместить каждый элемент на экране.
4. Выполнение JavaScript
Как и когда ресурсы JavaScript будут загружены, определяет, в какой-то момент они будут проанализированы, скомпилированы и выполнены. В разных браузерах для выполнения этой задачи используются разные механизмы JavaScript. Анализ JavaScript может быть дорогостоящим процессом с точки зрения ресурсов компьютера, в большей степени, чем другие типы ресурсов, поэтому его оптимизация так важна для достижения хорошей производительности. Прочтите этот фантастический пост, чтобы подробнее узнать, как работает движок JavaScript.
События загрузки
После того, как синхронно загруженный JavaScript и DOM будут полностью проанализированы и готовы, будет сгенерировано событие document.DOMContentLoaded. Для любых сценариев, которым требуется доступ к DOM, например, для управления им или прослушивания событий взаимодействия с пользователем, рекомендуется сначала дождаться этого события перед выполнением сценариев.
После того, как все остальное, например асинхронный JavaScript, изображения и т. д., завершили загрузку, запускается событие window.load.
5. Объединение DOM и CSSOM, для построения дерево рендеринга
Дерево рендеринга представляет собой комбинацию DOM и CSSOM и представляет все, что будет отображаться на странице. Это не обязательно означает, что все узлы в дереве рендеринга будут визуально присутствовать, например узлы со стилями opacity: 0 или visibility: hidden будут включены и могут быть прочитаны программой чтения с экрана и т. д., тогда как те, которые настроены на display: none будет исключены. Кроме того, такие теги, как <head>, не содержащие визуальной информации, всегда будут пропущены.
Как и в случае с движками JavaScript, разные браузеры имеют разные механизмы рендеринга.
6. Расчет макета и отрисовка результата
Теперь, когда у нас есть полное дерево рендеринга, браузер знает, что рендерить, но не знает, где рендерить. Следовательно, необходимо рассчитать макет страницы (то есть положение и размер каждого узла). Механизм рендеринга проходит дерево рендеринга, начиная с вершины и идя вниз, вычисляет координаты, в которых должен отображаться каждый узел.
И вуаля! В конце концов, у нас есть полностью отрисованная веб-страница!
От автора: после того как браузер получает HTML ответ от сервера, проходит еще множество этапов перед отрисовкой пикселей на экране. Последовательность действий, которую должен пройти браузер для первичной отрисовки страницы называется «путь критического рендеринга» или CRP.
Знание CRP невероятно полезно для понимания того, как можно улучшить производительность сайта. CRP проходит 6 этапов:
построение дерева DOM;
построение дерева CSSOM;
Практический курс по верстке адаптивного сайта с нуля!
Изучите курс и узнайте, как верстать современные сайты на HTML5 и CSS3
создание дерева рендеринга;
Построение дерева DOM
Дерево DOM (Document Object Model) – это объектное представление полностью распарсеной HTML страницы. Узлы создаются для каждого элемента/текста на странице, начиная от корневого элемента . Вложенные элементы представляются в виде дочерних узлов, все узлы хранят все атрибуты элементов. Например, тег a будет иметь атрибут href, привязанный к своему узлу.
Разберем для примера этот простой документ:
< title > Understanding the Critical Rendering Path < / title > < h1 > Understanding the Critical Rendering Path < / h1 >Код создает следующее дерево DOM:
Чем хорош HTML – его можно выполнять частями. Не нужно загружать весь документ, чтобы начать отрисовывать контент на странице. Однако другие ресурсы, например, CSS и JS могут блокировать рендеринг.
Построение дерева CSSOM
CSSOM (CSS Object Model) представляет собой объектное представление стилей DOM. Представление очень похоже на DOM, только к узлам добавляются стили, будь то явно прописанные или неявно унаследованные.
Для документа выше у нас есть файл style.css со следующими стилями:
Стили создают следующее дерево CSSOM:
CSS считается ресурсом, блокирующим рендеринг. То есть дерево рендеринга (см. ниже) не построится, пока не распарсится этот ресурс. Из-за своей каскадной природы CSS нельзя использовать частями, в отличие от HTML. Стили, объявленные в файле ниже, могут переписать значения и изменить предыдущие стили. Если мы будем использовать стили, объявленные сверху в файле, не дождавшись полного парсинга, это может привести к тому, что будут применены не те стили. CSS должен быть полностью распарсен перед тем, как переходить к следующему этапу.
CSS может также блокировать скрипты. JS файлы должны подождать, пока построится CSSOM.
Запуск JavaScript
JS считается ресурсом, блокирующим парсер. То есть парсинг HTML документа блокируется JS.
Когда парсер доходит до тега script, будь то внутренний или внешний, он останавливается и вытягивает код (если файл внешний) и запускает его выполнение. Вот почему необходимо размещать скрипты в конце документа, если они ссылаются на элементы.
Практический курс по верстке адаптивного сайта с нуля!
Изучите курс и узнайте, как верстать современные сайты на HTML5 и CSS3
Чтобы не блокировать парсер, JS можно загружать асинхронно с помощью атрибута async.
Последние годы мы видим в вебе два тренда: 1. Веб-страницы значительно выросли, особенно в плане запросов по требуемой полосе пропускания и загружаемым ресурсам (стили, скрипты, изображения, шрифты). 2. Выросло количество пользователей, просматривающих сайты с мобильных телефонов и планшетов.
Дома у большинства есть ПК и быстрый интернет. Но ничуть не меньше пользователей, находящихся в иных условиях. Даже быстрое соединение 4G в дороге решает не все проблемы — остается проблема с экономией трафика и скоростью рендеринга на мобильных устройствах.
Все это ведет к новому отношению к скорости загрузки страниц и их оптимизации. Google повышает в выдаче страницы, грузящиеся быстрее секунды. 1 секунда это принятое оптимальное время ответа страницы (10 мс это мгновенно, 3 секунды заставляют отменить загрузку сайта, а 10 секунд ожидания могут навсегда отпугнуть посетителей).
Но как этого достигнуть, не урезая функциональность и не ухудшая внешний вид?
Идея состоит не только в том, чтобы перенести сайта на быстрый сервер и максимально уменьшить размер страниц. Нужно оптимизировать всю цепочку событий, которые происходят при рендеринге страницы в окне браузера. Эта цепочка называется критический путь рендеринга.
От загрузки страницы до рендеринга
Google определяет критический путь рендеринга как цепь шагов браузера от загрузки кода и ресурсов до его отображения на экране вплоть до отдельных пикселов.
Это совершенно меняет понятие “скорость загрузки страницы”. Недостаточно просто быстро загрузить страницу — решающее значение, особенно для пользователей мобильных устройств, имеет скорость появления визуального отображения страницы на экране. Важен именно критический путь — так как далеко не весь код на странице производит что-либо в окне браузера.
Для оптимизации критического пути рендеринга и, соответственно, скорости рендеринга, давайте рассмотрим внимательней шаги по рендерингу страницы и их взаимодействие.
От чистого листа до содержания
Представьте себя на месте пользователя, заходящего на сайт. После ввода URL, браузер отправляет запрос на сервер и получает в качестве ответа следующий HTML:
Браузер парсит этот поток байтов кода в объектную модель документа (DOM). DOM это полное древовидное представление HTML-разметки:
Примечание: браузер строит DOM постепенно. Это значит, что он может начать парсинг сразу, как только получит первые фрагменты кода, постепенно добавляя к дереву узлы. И это может быть использовано в некоторых продвинутых, но эффективных методиках оптимизации.
На этой точке окно браузера пустое. Обратите внимание, как обрабатываются CSS, подключенные из <head> . Применение стилей это один из важнейших моментов рендеринга, поэтому стили должны загружаться сразу как только парсер дойдет до тега <link> .
Этот небольшой фрагмент CSS парсится в объектную модель CSS или CSSOM.
К сожалению, CSSOM не может строится постепенно, как DOM. Представьте, что в нашей таблице стилей, приведенной выше есть третья строка, например p < font-weight: normal; >, переписывающая первую декларацию. И именно по причине каскадирования и переписывания, мы должны дождаться полной загрузки CSS, перед тем как перейти к рендерингу. Пока CSS не загружен — рендеринг блокирован.
Как только браузер получает машинно-читаемое представление разметки и стилей, он переходит к построению дерева рендеринга — структуры, сочетающей DOM и CSSOM для всех видимых элементов:
Отметьте, что тег span не является частью дерева рендеринга (еще одна причина, по которой рендеринг не начинается без CSS — только в CSS есть информация об отображении/не отображении элементов на странице).
Дерево рендеринга это хорошее представление контента, который мы затем увидим в окне браузера. Браузер начинает показывать пиксели после еще двух шагов: макетирования и отрисовки. При макетировании рассчитываются позиции и размеры элементов в соответствии с областью просмотра. Отрисовка это уже сам процесс отрисовки элементов на экране.
Каждый раз, когда дерево рендеринга меняется (при использовании интерактивного JS, например) или меняется область просмотра (путем изменения размеров браузера или поворота мобильного устройства), запускается отрисовка.
Полностью критический путь рендеринга для нашего простого примера выглядят так:
Как насчет изображений
Фактически только HTML, CSS и JavaScript критически важны для рендеринга (это ресурсы, загрузка которых блокирует рендеринг страницы). Как это не удивительно, изображения не блокируют ни построение DOM, ни первоначальный рендеринг страницы. Посмотрите на вкладку сеть в инструментах разработчика Chrome:
Синяя вертикальная полоса это событие DOMContentLoaded , запускающееся после построения DOM. Изображения загружаются позже и поэтому не блокируют парсинг. Они блокируют событие Load (красная вертикальная полоса) — это событие означает, что все необходимые для страницы ресурсы скачаны и обработаны. Изображения, конечно, необходимо оптимизировать — но они не являются частью критического пути рендеринга.
А теперь JavaScript
JavaScript это мощный инструмент и он имеет огромное значение для критического пути. Давайте добавим в наш параграф небольшой скрипт:
Даже этот простой фрагмент кода демонстрирует, что скрипты могут изменять и DOM, и CSSOM. Так как JavaScript может добавлять узлы в DOM, парсер останавливает свою работу, пока скрипты не будут выполнены. JavaScript блокирует парсер.
JS в примере запрашивает цвет элемента, а это значит, что CSSOM должна быть готова до запуска скрипта. CSS должен быть загружен до скриптов.
Давайте оценим критический путь после избавления от инлайнового скрипта и замены его ссылкой на внешний файл JavaScript:
Внешний файл JavaScript требует дополнительный запрос — инлайновый скрипт обходится без этого. Также отметьте — неважно какой файл, CSS и JS, будет загружен первым, парсинг CSS всегда начинается раньше. Если CSSOM построена, тогда уже выполняется скрипт. И только после этого парсер DOM разблокируется и завершает работу. Даже в простом сайте из нашего примера, находятся свои блокираторы, вмешивающиеся в процесс рендеринга.
Теперь, после того как мы выяснили, какие части сайта важны для рендеринга страницы и как они влияют друг на друга, мы рассмотрим конкретные методики оптимизации.
Три шага для оптимизации критического пути рендеринга
Есть три направления по которым мы можем оптимизировать критический путь рендеринга, увеличив скорость появления в браузере видимого результата для пользователя. Учитывайте, что оптимизация это всегда тщательные расчеты и компромиссы. И, к сожалению, нет универсального сценария оптимизации. Важно учитывать информацию из средств разработчика в браузерах, а также применять иные инструменты.
1. Минимизируйте объем трафика, передающегося на сайт.
Это самый очевидный совет, но вы удивитесь, узнав, как много сайтов до сих пор не используют эту простейшую оптимизацию - ведь чем меньше ваш сайт, тем быстрее он загружается и отрисовывается.
Минифицируйте, сжимайте и кэшируйте ресурсы вашего сайта, а также его разметку. Да, HTML также блокирует рендеринг. Многие системы сборки (наиболее известные — Grunt и Gulp) поддерживают плагины минификации и очистки от лишних пробелов и комментариев.
Сжатие сокращает время загрузки страницы, а кэширование позволяет экономить трафик. Вместо загрузки по сети, критически важные ресурсы сохраняются в локальной копии.
Примечание: При минификации разметки HTML вы рискуете, что контент и стили отобразятся некорректно. Например, если вы разделяли строчно-блочные элементы пробелами, после минификации пробелы исчезнут вместе с отступом. Применяйте минификацию разметки HTML осторожно.
2. Минимизируйте блокирование рендеринга загрузкой CSS
Обработка CSS это важная часть процесса рендеринга. CSS блокирует не только рендеринг, но и выполнение скриптов. Поэтому совершенно очевидно главное правило по загрузке: максимально быстро — подключаем link со стилями в head . Также можно уменьшить размер CSS с помощью медиа-запросов. Например, для нашего сайта есть стандартные стили, стили для портретной ориентации и стили для печати. Имеет смысл разбить код на несколько файлов и подключать их в случае необходимости:
Основной файл стилей уменьшится, а значит уменьшится и время блокировки рендеринга. Стили для печати будут использоваться только при печати и не будут загружаться в остальных случаях. Файл CSS для портретной ориентации будет загружаться же только при повороте мобильного устройства. Очевидно, что мы можем использовать медиа-запросы, чтобы отдельно загружать стили, необходимые только в особых ситуациях. Это уменьшает размер подключаемого блокирующего CSS, а значит, уменьшает и время, затрачиваемое браузером на парсинг. Примечание: Браузер по прежнему будет загружать дополнительные стили, но это будет происходить в низком приоритете, параллельно процессу рендеринга. Также в отдельных ситуациях можно инлайнировать блокирующий CSS — это позволяет сэкономить запросы и ограничить браузер парсингом HTML.
Как я упоминал, это все компромиссные меры. Иногда это может помочь, а иногда излишне увеличит размер критически важного CSS, вставленного в разные файлы.
Есть несколько автоматических инструментов для оптимизации CSS:
3. Минимизируйте блокирующий рендеринг JavaScript
Точно так же как и CSS, JavaScript можно включать напрямую в разметку, чтобы сэкономить на сетевых запросах.
В лучшем случае вы не подключаете JS до первоначальной загрузки страницы. Если это не возможно, попытайтесь отложить выполнение JS до события загрузки.
Также внимательно проверяйте свои и чужие скрипты. Если они не взаимодействуют с DOM или CSSOM, вы можете загрузить их асинхронно. Это делается просто:
С атрибутом async вы говорите браузеру, что необязательно немедленно исполнять скрипт по ссылке из HTML. Браузер строит DOM и только после построения DOM запускает выполнение скрипта. Представьте скрипт app.js, взаимодействующий только с Гугл-аналитикой и социальными сетями — если это скрипт не трогает DOM или CSSOM, он отличный кандидат на асинхронную загрузку.
Заключение
Большая часть статьи почерпнута из следующих источников:
- Документация от Google по основам Web особенно раздел про критический путь рендеринга.
- Курс Udacity по оптимизации производительности сайтов.
- Бесплатная онлайн-книга Ильи Григорика “Высокопроизводительная работа браузера”
- Понятие скорости загрузки страницы изменилось — это не просто скорость загрузки, это скорость рендеринга.
- К критическим участкам рендеринга относятся все шаги по превращению ресурсов в картинку в браузере:DOM и CSSOM, JavaScript, дерево рендеринга, макетирование и отрисовка.
- HTML блокирует рендеринг, но DOM может строиться постепенно.
- CSS блокирует рендеринг и выполнение скриптов, его можно аккуратно оптимизировать с помощью медиа-запросов и инлайнирования.
- JS блокирует парсинг, осторожно используйте его до стадии первоначальной загрузки, отложите выполнение или загружайте асинхронно.
- Не забывайте про размер — минифицируйте, сжимайте, кэшируйте.
Активней пользуйтесь инструментами, такими как Chrome DevTools, PageSpeed Insights или WebPagetest, чтобы понять, какие оптимизации возможны и необходимы.
Скорость рендеринга страницы может иметь решающее значение для ваших посетителей, которые обычно не привыкли долго ждать. Учитывайте это при разработке и поддержке сайта, от улучшения его производительности вы тоже выиграете.
DOM и CSSOM образуют модель визуализации. С ее помощью браузер формирует из всех видимых объектов макет, а затем выводит пиксели на экран. Чтобы ускорить загрузку страницы, нужно оптимизировать каждый из этих этапов.
В предыдущей главе мы узнали о том, как на основании HTML- и CSS-файлов строятся модели DOM и CSSOM. Эти независимые друг от друга модели отвечают за разные аспекты страницы: DOM описывает контент, а CSSOM - стили, которые будут к нему применены. Рассмотрим, как браузер объединяет эти модели и выводит страницу на экран.
- Браузер объединяет DOM и CSSOM, формируя модель визуализации.
- Модель визуализации содержит только те объекты, которые нужны для вывода страницы на экран.
- Далее формируется макет, отражающий расположение и размер каждого объекта.
- Наконец, объекты выводятся на экран.
Для начала браузер формирует модель визуализации, в которой всем видимым объектам из модели DOM присваиваются наборы стилей из модели CSSOM.
Для формирования модели визуализации браузер выполняет следующие действия:
- Начиная с основания модели DOM, находит все видимые объекты.
- Этот этап не затрагивает элементы, которые не будут видны на странице, например теги скриптов, метатеги и т. п.
- Он также не затрагивает объекты, помеченные как невидимые с помощью CSS. Взгляните на приведенную выше схему: объект span отсутствует в модели визуализации, потому что ему присвоен параметр display: none .
- Находит в CSSOM наборы стилей и присваивает их соответствующим объектам.
- Формирует модель из видимых объектов, их содержания и стилей.
Создав модель визуализации, браузер на шаг приблизился к выводу страницы на экран! Теперь можно приступить к формированию макета.
Браузер уже определил, какие объекты будут видны на странице и какие стили нужно им присвоить. Пришло время создать макет, т. е. выяснить, какого размера будут объекты и как их нужно расположить в области просмотра.
Для этого браузер вычисляет геометрическую форму объектов, анализируя модель визуализации с самого начала. Рассмотрим простой пример:
В теле этой страницы есть два блока div. Ширина родительского блока - 50% от области просмотра, а вложенного - 50% от родительского, т. е. 25% экрана.
Сформировав макет, браузер получает блочную модель, точно отражающую расположение и размер каждого объекта в области просмотра. Все относительные показатели преобразуются в абсолютное положение пикселей на экране.
Наконец, когда браузеру известно, какие объекты будут отображаться на странице, где их разместить и какие стили им нужно присвоить, можно приступать к следующему этапу - выводу страницы на экран. Этот этап также называется визуализацией или растеризацией.
Как вы наверняка заметили, браузеру нужно выполнить множество действий, на которые зачастую уходит немало времени. Чтобы оптимизировать время загрузки, продолжительность каждого этапа можно отслеживать с помощью инструментов разработчика в Chrome. Рассмотрим этап формирования макета на нашем первом примере Hello World:
- Событие Layout на вкладке Timeline отражает время, затраченное на формирование макета, а также на определение положения и размера объектов.
- Сформировав макет, браузер переходит к этапам Paint Setup и Paint для преобразования модели визуализации в пиксели.
Время, затрачиваемое на создание модели визуализации и макета, а также на вывод пикселей, варьируется в зависимости от размера документа, сложности стилей и мощности устройства. Чем больше HTML-файл, тем больше работы нужно проделать браузеру. Чем сложнее стили, тем больше времени потребуется на визуализацию (например, текст с эффектом тени обработать сложнее, чем простой одноцветный).
Тем временем, визуализация завершилась, и наша страница появилась в области просмотра!
Давайте вспомним, какие действия выполнил браузер:
- Обработка HTML-разметки и создание модели DOM.
- Обработка CSS-файла и создание модели CSSOM.
- Создание модели визуализации из DOM и CSSOM.
- Определение формы и расположения объектов, создание макета.
- Вывод объектов на экран.
Вот что нужно проделать для визуализации даже такой простой страницы, как наша. А если мы внесем изменения в DOM или CSSOM, браузеру придется повторить все действия, чтобы определить, как вывести пиксели на экран.
Чтобы оптимизировать процесс визуализации, нужно уменьшить время, затрачиваемое на выполнение пяти действий из списка выше. В результате контент будет выводиться на экран быстрее, время обновления сократится, а вместе с этим возрастет частота обновления интерактивного контента.
Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Читайте также: