Процесс рендеринга в браузере и оптимизация производительности

внешний интерфейс программист JavaScript браузер Язык программирования Chrome HTML CSS
Процесс рендеринга в браузере и оптимизация производительности

Все знают, что прикладной слой всемирного интервета используетHTTPпротокола и использовать браузер в качестве точки входа для доступа к ресурсам в сети. Когда пользователь использует браузер для посещения веб-сайта, ему необходимо пройтиHTTPПротокол отправляет запрос на сервер, после чего сервер возвращаетHTMLфайл и ответная информация. В этом случае браузерHTMLфайл для парсинга и рендеринга (этот этап также включает в себя запрос неинлайновыхCSSфайл сJavaScriptфайлы или другие ресурсы) и, наконец, отобразить страницу для пользователя.

Теперь, когда мы знаем, что рендеринг веб-страниц выполняется браузером, если скорость загрузки страницы веб-сайта слишком медленная, взаимодействие с пользователем будет недостаточно удобным В этой статье представлены некоторые основные решения по оптимизации производительности браузера с объяснением процесса. рендеринга страниц браузером в деталях. Позвольте браузеру быстрее отображать ваши веб-страницы и быстро реагировать, чтобы улучшить взаимодействие с пользователем.

Автор этой статьи:SylvanasSun(sylvanas.sun@gmail.com).Для перепечатки следующий абзац следует разместить в начале статьи (сохранить гиперссылку).
Эта статья была впервые опубликована сSylvanasSun Blog, ссылка на описание:sylva, то есть sun.GitHub.IO/2017/10/03/…

критический путь рендеринга


Браузер получает возвращенныйHTML,CSSа такжеJavaScriptПроцесс рендеринга байтовых данных, их разбор и преобразование в пиксели называется критическим путем рендеринга. Оптимизируя критический путь рендеринга, вы можете сократить время, необходимое браузеру для рендеринга страницы.

Браузер перед рендерингом страницы, которую нужно построитьDOMдерево сCSSOMДерево(если нетDOMдерево иCSSOMДерево не может определить структуру и стиль страницы, поэтому эти два должны быть построены в первую очередь).

DOMполное название дереваDocument Object ModelОбъектная модель документа, этоHTMLа такжеXMLПрограммный интерфейс к документу, обеспечивающий структурированное представление документа и определяющий способ доступа программ к этой структуре.(НапримерJavaScriptчерезDOMуправлять структурой, стилем и содержанием).DOMРазберите документ на набор узлов и объектов, скажем,WEBСтраница на самом деле являетсяDOM.

CSSOMполное название дереваCascading Style Sheets Object ModelОбъектная модель каскадных таблиц стилей, которая связана сDOMЗначение дерева не сильно отличается, за исключением того, что оноCSSколлекция предметов.

Построить дерево DOM и дерево CSSOM


Браузер получает из сети или с жесткого дискаHTMLПосле байтовых данных он пройдет через процесс разбора байтов вDOMДерево:

  • кодирование:первыйHTMLПреобразование необработанных байтовых данных в символы указанной кодировки файла.

  • токенизация: тогдаБраузер будетHTMLСпецификация для преобразования строк в различные токены(Такие как<html>,<body>Такие теги, а также строки и атрибуты в тегах преобразуются в токены, каждый из которых имеет особое значение и набор правил). Маркер записывает начало и конец тега, и эта функция может легко определить, является ли тег вложенным тегом (при условии, что<html>а также<body>две метки, когда<html>Токен тега еще не встретил свой конечный токен</html>только что встретил<body>Tag Token, затем<body>то есть<html>подтег).

  • Создать объект:Затем каждый токен преобразуется в объект (этот объект является объектом узла), который определяет его свойства и правила.

  • Сборка завершена:DOMПостроение дерева завершено, и вся коллекция объектов похожа на древовидную структуру.. Некоторые могут задаться вопросом, почемуDOMявляется древовидной структурой, потому что между тегами существует сложная связь родитель-потомок, и древовидная структура может просто интерпретировать эту связь (CSSOSТочно так же каскадные стили также имеют отношения родитель-потомок. Например:div p {font-size: 18px}, сначала найдет всеpтег и определить, является ли его родительский тегdivПозже будет принято решение, использовать ли этот стиль для рендеринга).

весьDOMСобственно процесс построения дерева таков:байт -> символ -> токен -> объект узла -> объектная модель, пример будет нижеHTMLКод и сопровождающие его картинки более наглядно объясняют этот процесс.

<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="style.css" rel="stylesheet">
    <title>Critical Path</title>
  </head>
  <body>
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg"></div>
  </body>
</html>

DOM树构建过程
Процесс построения дерева DOM

когда вышеHTMLкод соответствует<link>тег, браузер отправит запрос на получениеCSSфайл (используя встроенныйCSSМожно опустить запрошенный шаг для увеличения скорости, но не обязательно терять модульность и ремонтопригодность для этой скорости),style.cssСодержание следующее:

body { font-size: 16px }
p { font-weight: bold }
span { color: red }
p span { display: none }
img { float: right }

браузер становится внешнимCSSПосле данных файла он будет построен какDOMНачните строить как деревоCSSOMДерево, особой разницы в этом процессе нет.

CSSOM树
CSSOM-дерево

Если вы хотите более подробно ознакомиться с построением критического пути рендеринга, вы можете использоватьChromeв инструментах разработчикаTimelineОн записывает различные операции браузера от запроса ресурсов страницы до рендеринга, и даже может записывать процесс определенного периода времени (рекомендуется не заходить на слишком большие сайты, информация будет более загроможденной).

Timeline
Timeline

Построить дерево рендеринга


в зданииDOMдерево иCSSOMПосле дерева у браузера просто есть две отдельные коллекции объектов,DOMДерево описывает структуру и содержание документа,CSSOMДерево описывает правила стиля, применяемые к документу,Чтобы отобразить страницу, вам нужноDOMдерево сCSSOMдерево вместе, который является деревом рендеринга.

渲染树
визуализировать дерево

  • Браузер запустится сDOMКорневой узел дерева начинает обход каждого видимого узла (невидимые узлы естественно не нужно рендерить на страницу, к невидимым узлам тоже относятсяCSSуже настроенdisplay: noneсвойства узла, стоит отметить, чтоvisibility: hiddenАтрибут не считается невидимым, его семантика заключается в том, чтобы скрыть элемент, но элемент по-прежнему занимает пространство макета, поэтому он будет отображаться как пустой блок).

  • Для каждого видимого узла найдите подходящийCSSПравила стиля и применения.

  • Строится дерево рендеринга, и каждый узел является видимым узлом и содержит свое содержимое и соответствующие правила стиля.

После построения дерева рендеринга браузер получает содержимое и стиль каждого видимого узла, и следующим шагом являетсяНеобходимо рассчитать точное положение и размер каждого узла в окне, что является фазой компоновки.

CSSМентальная модель, называемая блочной моделью, используется для представления расстояния между каждым узлом и другими элементами.Коробочная модель включает внешнее поле (Margin), заполнение (Padding),Рамка(Border),содержание(Content). Каждая вкладка на странице на самом деле представляет собой поле.

盒子模型
коробочная модель

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

<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Critial Path: Hello world!</title>
  </head>
  <body>
    <div style="width: 50%">
      <div style="width: 50%">Hello world!</div>
    </div>
  </body>
</html>

上述代码的布局结果
Результат макета приведенного выше кода

когдаLayoutБраузер излучает, как только событие макета завершаетсяPaint Setupа такжеPaintсобытие, чтобы начать рисовать дерево рендеринга в пикселях, время, необходимое для рисования, следуетCSSСложность стиля пропорциональна.После завершения рисования пользователь может увидеть окончательный эффект отрисовки страницы.

Нам может потребоваться 1-2 секунды, чтобы отправить запрос на веб-страницу и получить отрендеренную страницу, но на самом деле браузер проделал большую часть работы, упомянутой выше.Подытожим весь процесс критического пути рендеринга браузера:

  • иметь дело сHTMLМаркируйте данные и генерируйтеDOMДерево.

  • иметь дело сCSSМаркируйте данные и генерируйтеCSSOMДерево.

  • БудуDOMдерево сCSSOMДеревья объединяются вместе для создания дерева рендеринга.

  • Пройдите по дереву рендеринга, чтобы начать компоновку и вычислить информацию о положении каждого узла.

  • Каждый узел будет нарисован на экран.

Схема оптимизации блокировки рендеринга


Чтобы браузер мог отобразить страницу, он должен сначала создатьDOMдерево сCSSOMдерево, еслиHTMLа такжеCSSФайловая структура очень большая и сложная, что, очевидно, серьезно влияет на скорость загрузки страницы.

Так называемый блокирующий ресурс рендеринга означает, что после отправки запроса на ресурс вам необходимо сначала построить соответствующий ресурс.DOMдерево илиCSSOMдерево, такое поведение явно задерживает начало операции рендеринга.HTML,CSS,JavaScriptвсе ресурсы, которые будут блокировать рендеринг.HTMLтребуется (нетDOMТакже говорить о рендеринге), но и отCSSа такжеJavaScriptНачните оптимизировать, чтобы максимально уменьшить блокировку.

Оптимизировать CSS


если ты позволишьCSSРесурсы используются только при определенных условиях, поэтому их можно сначала загрузить без созданияCSSOMдерево, которое позволит браузеру блокировать рендеринг, а затем строить только при соблюдении определенных условийCSSOMДерево.

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

<!-- 没有使用媒体查询,这个css资源会阻塞渲染  -->
<link href="style.css"    rel="stylesheet">
<!-- all是默认类型,它和不设置媒体查询的效果是一样的 -->
<link href="style.css"    rel="stylesheet" media="all">
<!-- 动态媒体查询, 将在网页加载时计算。
根据网页加载时设备的方向,portrait.css 可能阻塞渲染,也可能不阻塞渲染。-->
<link href="portrait.css" rel="stylesheet" media="orientation:portrait">
<!-- 只在打印网页时应用,因此网页首次在浏览器中加载时,它不会阻塞渲染。 -->
<link href="print.css"    rel="stylesheet" media="print">

Использование медиазапросов позволяетCSSАктивы не блокируют рендеринг при первой загрузке, но либоCSSЗапрос на загрузку ресурсов не будет проигнорирован, браузер все равно сначала загрузит файл CSS.

Оптимизировать JavaScript


когда браузерHTMLПарсер обнаружилscriptДелайте паузы при маркировкеDOM, затем передать управлениеJavaScriptдвигатель, то двигатель начнет выполнятьJavaScriptскрипт, браузер не возобновит работу с того места, где он остановился, до тех пор, пока выполнение не завершится, а затем продолжит сборкуDOM. каждый раз выполнятьJavaScriptСкрипты плохо блокируютсяDOMСтроительство дерева, еслиJavaScriptСкрипт тоже работаетCSSOM, и именно этоCSSOMЕще не скачал и не собрал, браузеры даже задерживают выполнение скрипта и сборкуDOM, до завершения егоCSSOMскачать и построить. Очевидно, еслиJavaScriptНеправильное расположение реализации, что серьезно повлияет на скорость рендеринга.

в коде нижеJavaScriptСкрипт не работает, потому чтоDOMДерево еще не построено<p>При маркировке,JavaScriptСкрипт уже начал выполняться. Поэтому часто людиHTMLНапишите встроенный в нижней части файлаJavaScriptкод или используйтеwindow.onload()а такжеJQueryсередина$(function(){})(Между этими двумя функциями есть некоторые различия,window.onload()событие, запускаемое после ожидания полной загрузки страницы, и$(function(){})существуетDOMбудет выполняться после построения дерева).

<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="style.css" rel="stylesheet">
    <title>Hello,World</title>
    <script type="text/javascript">
        var p = document.getElementsByTagName('p')[0];
        p.textContent = 'SylvanasSun';    
    </script>
  </head>
  <body>
    <p>Hello,World!</p>
  </body>
</html>

использоватьasyncможет сообщить браузеру, что скрипт не нужно выполнять в указанном месте, чтобы браузер мог продолжить созданиеDOM,JavaScriptСкрипт начнет выполняться, когда будет готов, что значительно улучшит производительность загрузки первой страницы (asyncтолько вsrcиспользуется в этикетке, то есть на внешнюю ссылкуJavaScriptдокумент).

<!-- 下面2个用法效果是等价的 -->
<script type="text/javascript" src="demo_async.js" async="async"></script>
<script type="text/javascript" src="demo_async.js" async></script>

Оптимизация критического пути рендеринга


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

Предположим, естьHTMLстраница, которая представляет толькоCSSВнешние файлы:

<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="style.css" rel="stylesheet">
  </head>
  <body>
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg"></div>
  </body>
</html>

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

Во-первых, браузеру необходимо отправить запрос на сервер для полученияHTMLфайл, получитьHTMLНачать сборку после файлаDOMдерево, встреча<link>тег, браузер должен снова сделать запрос к серверу, чтобы получитьCSSфайл, затем продолжить сборкуDOMдерево иCSSOMдерево, браузер объединяет дерево рендеринга, выполняет расчет макета в соответствии с деревом рендеринга, выполняет операцию рисования, и рендеринг страницы завершается.

Существует несколько терминов, используемых для описания производительности критического пути рендеринга:

  • Ключевые ресурсы: ресурсы, которые могут блокировать первый рендеринг веб-страницы (два на картинке выше,HTMLфайл и внешнийCSSдокументstyle.css).

  • Длина критического пути: количество циклов или общее время, необходимое для получения ключевых ресурсов (2 или более на рисунке выше, одно приобретение).HTMLфайл, получить его сразуCSSДокумент, это число основано наTCPМаксимальное окно перегрузки протокола, файл не может быть передан в рамках одного соединения).

  • Критические байты: сумма размеров файлов всех критических ресурсов (на9KB).

Далее изменились требования к коду дела, в него добавили новыйJavaScriptдокумент.

<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="style.css" rel="stylesheet">
  </head>
  <body>
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg"></div>
    <script src="app.js"></script>
  </body>
</html>

JavaScriptфайл заблокированDOMдерево построено и выполняетсяJavaScriptСкрипт также должен сначала дождаться сборкиCSSOMTree, ключевые характеристики пути рендеринга на приведенном выше рисунке следующие:

  • Ключевые ресурсы: 3 (HTML,style.css,app.js)

  • Критическая длина пути: 2 или более (браузер загружает вместе за одно соединение)style.cssа такжеapp.js)

  • Ключевые байты: 11 КБ

Теперь мы хотим оптимизировать критический путь рендеринга, сначала<script>Добавить асинхронный атрибут в тегasync, так что браузерHTMLПарсер не будет блокировать этоJavaScriptфайл.

<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="style.css" rel="stylesheet">
  </head>
  <body>
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg"></div>
    <script src="app.js" async></script>
  </body>
</html>

  • Ключевые ресурсы: 2 (app.jsЗагружается асинхронно и не станет ресурсом, блокирующим рендеринг)

  • Длина критического пути: 2 или более

  • Ключевые байты: 9 КБ (app.jsбольше не является критическим ресурсом, поэтому его размер не учитывается)

рядом сCSSВыполните оптимизацию, например, добавьте медиа-запросы.

<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="style.css" rel="stylesheet" media="print">
  </head>
  <body>
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg"></div>
    <script src="app.js" async></script>
  </body>
</html>

  • Основные ресурсы: 1 (app.jsдля асинхронной загрузки,style.cssОн будет использоваться только при печати, поэтому толькоHTMLключевой ресурс, то есть когдаDOMКогда дерево построено, браузер начинает рендеринг)

  • Длина критического пути: 1 или более

  • Основные байты: 5 КБ

Оптимизация критического пути рендеринга — это оптимизация критических ресурсов, длины критического пути и критических байтов.. Чем меньше критических ресурсов, тем меньшую подготовку должен сделать браузер перед рендерингом, аналогично длина критического пути и байты ключа связаны с эффективностью браузера при загрузке ресурсов, чем их меньше, тем быстрее браузер может загружать ресурсы.

Другие решения по оптимизации


За исключением асинхронной загрузкиJavaScriptПомимо использования медиа-запросов, существует множество других схем оптимизации, которые могут ускорить первую загрузку страницы.Эти схемы можно использовать в комбинации, но основная идея все равно оптимизируется для критического пути рендеринга.

Загрузить часть HTML


Когда сервер получает запрос, он отвечает толькоHTMLначальная частьHTMLКонтент передается по мере необходимостиAJAXполучать. Поскольку сервер отправляет только частьHTMLфайл, который позволяет построитьDOMНагрузка на дерево значительно снижена, так что пользователь чувствует, что страница загружается быстро.

Обратите внимание, что этот метод нельзя использовать вCSS, браузер не позволяетCSSOMСтройте только начальную часть, иначе точный стиль определить невозможно.

компрессия


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

Сжатие данных фактически перекодирует их с меньшим количеством битов.. На сегодняшний день существует множество алгоритмов сжатия, и у каждого из них разные поля действия, и сложность их тоже разная, но я не буду здесь рассказывать о деталях алгоритма сжатия, а заинтересованные друзья могут сами погуглить.

справаHTML,CSSа такжеJavaScriptПрежде чем эти файлы будут сжаты, также требуется избыточное сжатие.Так называемое избыточное сжатие предназначено для удаления избыточных символов, таких как комментарии, пробелы и символы новой строки.. Эти символы полезны для программистов, ведь неформатированный код ужасно читабелен, но для браузеров они бессмысленны, а удаление этой избыточности может уменьшить объем данных в файле.После выполнения избыточного сжатия сами данные дополнительно сжимаются с использованием алгоритма сжатия,НапримерGZIP(GZIP— алгоритм сжатия общего назначения, который работает с любым потоком байтов, запоминает то, что он видел раньше, а затем пытается найти и заменить дубликаты. ).

HTTP-кеширование


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

Браузер поставляется сHTTPФункция кэширования должна только убедиться, что заголовок каждого ответа сервера содержит следующие атрибуты:

  • ETag:ETag — токен сквозной проверки, который проверяет наличие обновлений ресурса и не передает никаких данных, если ресурс не изменился.. Когда браузер отправляет запрос, он отправляет ETag на сервер, и сервер проверяет токен в соответствии с текущим ресурсом (обычно ETagHashПосле отпечатка), если ресурс не изменился, сервер вернет304 Not Modifiedответ, браузеру не нужно повторно загружать ресурс, но он продолжает повторно использовать кеш.

  • Кэш-Контроль:Cache-Control определяет стратегию кэширования, которая указывает, при каких условиях ответ может быть кэширован и как долго он может кэшироваться..

    • no-cache: no-cache означает, что вы должны сначала подтвердить с сервером, изменился ли возвращаемый ответ, а затем использовать ответ для удовлетворения последующих запросов на тот же URL (каждый раз запрос будет отправлен на сервер в соответствии с ETag для подтверждения изменения, если не изменится, браузер не скачает ресурс).

    • no-store: no-store напрямую запрещает браузеру и всем промежуточным кешам сохранять любую версию возвращаемого ответа. Проще говоря, эта политика отключает любое кэширование и загружает ответ сервера полностью при каждой отправке запроса.

    • public&private: если ответ помечен как общедоступный, даже если он имеет связанныйHTTPАутентификация и даже коды состояния ответов обычно не кэшируются, и браузеры могут кэшировать ответы. Если ответ помечен как частный, то ответ обычно кэшируется только для одного пользователя, поэтому промежуточный кэш (CDN) не может кэшировать его.

    • max-age: max-age определяет максимальное время кэширования от времени запроса в секундах.

Предварительная загрузка ресурсов


Pre-fetchingЭто способ побудить браузер предварительно загрузить ресурсы, которые пользователь может использовать позже.

использоватьdns-prefetchдля продвиженияDNSразрешить, чтобы вы могли позже быстро получить доступ к другому имени хоста (браузер будет разрешать и кэшировать доменное имя на веб-странице при загрузке веб-страницы, поэтому вам не нужно выполнять дополнительное разрешение DNS во время последующих посещений, уменьшая время ожидания пользователя время и повышение скорости загрузки страницы).

<link rel="dns-prefetch" href="other.hostname.com">

использоватьprefetchСвойства могут предварительно загружать ресурсы, но это имеет самый низкий приоритет.

<link rel="prefetch"  href="/some_other_resource.jpeg">

Chromeс разрешенияsubresourceатрибут указывает ресурс загрузки с наивысшим приоритетом (когда все атрибутыsubresourceПосле завершения загрузки ресурсов начнется загрузка.prefetchресурс).

<link rel="subresource"  href="/some_other_resource.js">

prerenderСтраница может быть предварительно отрендерена и скрыта, и тогда открытие страницы пропустит этап отрисовки и представит ее непосредственно пользователю (рекомендуется предварительно отрендерить страницу, которую пользователь должен посетить следующей, иначе выигрыш перевесит усиление).

<link rel="prerender"  href="//domain.com/next_page.html">

использованная литература