Я нарисовал 20 картинок, чтобы подробно объяснить принцип работы браузерного движка рендеринга.

внешний интерфейс JavaScript браузер
Я нарисовал 20 картинок, чтобы подробно объяснить принцип работы браузерного движка рендеринга.

Эта статья участвовала в "Проект «Звезда раскопок»”, чтобы выиграть творческий подарочный пакет и бросить вызов творческим поощрительным деньгам.


Сегодня узнаем как работает браузерный движок рендеринга В статье много статей Рекомендуется собрать их перед изучением!

Давайте сначала взглянем на архитектурную схему браузера Chrome:浏览器渲染原理-进程.pngОбычно HTML, CSS, JavaScript и другие файлы, которые мы пишем, будут отображать страницу после запуска браузера, так как же они преобразуются в страницы? В чем причина этого? Этот процесс реализуется процессом рендеринга браузера. Основная задача процесса рендеринга браузера состоит в том, чтобыПреобразуйте статические ресурсы в визуальный интерфейс: 浏览器渲染原理.pngДля браузера посередине это черный ящик Давайте посмотрим, как этот черный ящик преобразует статические ресурсы во внешние интерфейсы. Из-за сложного механизма рендеринга модуль рендеринга в процессе выполнения будет разделен на множество подэтапов, через которые проходят входные статические ресурсы, и, наконец, страница будет выведена. Мы называем поток обработки конвейером рендеринга, и его общий поток показан на следующем рисунке:浏览器渲染原理-第 2 页.pngЗдесь пять основных процессов:

  • Построение DOM-дерева: механизм рендеринга использует анализатор HTML (вызывающий анализатор XML) для анализа HTML-документа и преобразует каждый элемент HTML в узел DOM один за другим, тем самым создавая дерево DOM;
  • Построение дерева CSSOM: синтаксический анализатор CSS анализирует CSS, преобразует его в объекты CSS, собирает эти объекты CSS и строит дерево CSSOM;
  • Построение дерева рендеринга: после построения дерева DOM и дерева CSSOM браузер построит дерево рендеринга на основе этих двух деревьев;
  • Макет страницы: после построения дерева рендеринга определяются позиционные отношения элементов и применяемые стили.В это время браузер вычисляет размер и абсолютное положение всех элементов;
  • рисунок страницы: после завершения макета страницы браузер преобразует каждый слой страницы в пиксели в соответствии с результатами обработки и декодирует все медиафайлы.

Для этих пяти процессов каждая стадия имеет соответствующие продукты, а именно:DOM-дерево, CSSOM-дерево, рендер-дерево, блочная модель, интерфейс.

На следующем рисунке показаны модули, соответствующие каждому этапу рабочего процесса механизма визуализации:

image.pngКак видно из рисунка, основными модулями движка рендеринга являются:

  • парсер HTML: анализ HTML-документов, основная функция — преобразование HTML-документов в деревья DOM;
  • CSS-парсер: вычислить каждый элемент объекта в DOM, чтобы получить информацию о стиле для построения дерева рендеринга;
  • Интерпретатор JavaScript: используйте JavaScript для изменения содержимого веб-страницы, правил CSS и т. д. Интерпретатор JavaScript может интерпретировать код JavaScript и изменять правила содержания и стиля веб-страниц через интерфейс DOM и интерфейс CSSOM, тем самым изменяя результат рендеринга;
  • Макет страницы: после создания DOM механизм рендеринга объединяет объекты элементов в нем с правилами стиля, чтобы получить дерево рендеринга. Макет предназначен для дерева рендеринга, и вычисляется информация о макете, такая как размер и положение каждого элемента.
  • рисунок страницы: Используйте графическую библиотеку, чтобы нарисовать дерево рендеринга после расчета макета в результат визуального изображения.

Давайте посмотрим, что делает каждый из этих процессов.

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

Прежде чем говорить о построении дерева DOM, нам сначала нужно знать,Зачем строить DOM-дерево?Это связано с тем, что браузеры не могут напрямую понимать и использовать HTML, поэтому HTML необходимо преобразовать в структуру, понятную браузерам, — дерево DOM.

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

浏览器渲染原理-树2.png

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

После разговора о древовидной структуре давайте вернемся к теме и посмотрим, что такое DOM-дерево. На странице каждый тег HTML анализируется браузером в объект документа. HTML по сути является вложенной структурой.Во время синтаксического анализа каждый объект документа будет организован в древовидную структуру, и все объекты документа будут навешены на документ.Этот метод организации является самой базовой структурой HTML - Модель объекта документа (DOM) , каждый объект документа этого дерева называется узлом DOM. ​

В движке рендеринга DOM выполняет три функции:

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

Внутри механизма рендеринга синтаксический анализатор HTML отвечает за преобразование потока байтов HTML в структуру DOM.Процесс преобразования выглядит следующим образом:浏览器渲染原理-DOM树3.png

1. Поток символов → слово (токен)

Структура HTML сначала разбивает поток байтов на токены с помощью токенизатора. Токен делится на токен тега и токен текста. Давайте посмотрим, как разбивается HTML-код:

<body>
    <div>
        <p>hello world</p>
    </div>
</body>

Для этого кода его можно разбить на слова:浏览器渲染原理-第 10 页.pngКак видите, Tag Token делится на StartTag и EndTag,<body>,<div>,<p>это StartTag ,</body>,</div>,</p>Это EndTag, который соответствует синему и красному блокам на рисунке соответственно, а текст Token соответствует зеленому блоку. ​

Здесь символы разбиваются на токены с помощью конечного автомата.Так называемый конечный автомат состоит в том, чтобы разделить признаки каждого слова на независимые состояния один за другим, а затем объединить характерные признаки всех слов, чтобы сформировать структуру связанного графа. Так зачем использовать конечный автомат? Потому что каждый раз, когда читается символ, принимается решение, и эти решения связаны с текущим состоянием. ​

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

2. Word (токен) → DOM-дерево

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

  • Если токенизатор разбираетStartTag Token, синтаксический анализатор HTML создаст узел DOM для маркера, а затем добавит узел в дерево DOM, а его родительский узел — это узел, сгенерированный соседним элементом в стеке;
  • Если токенизатор разбираеттекст Token, то будет сгенерирован текстовый узел, а затем узел будет добавлен в DOM-дерево.Текстовый токен не нужно запихивать в стек, а его родительским узлом является DOM-узел, соответствующий текущему токену наверху стека;
  • Если токенизатор разбираетEndTag Token, например EndTag div, парсер HTML проверит, является ли элемент в верхней части стека Token элементом div StarTag, и если да, он извлечет элемент div StartTag из стека, указывая на то, что анализ элемента div завершен. .

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

Давайте посмотрим, как работает этот стек токенов со следующей структурой HTML:

<html>
    <body>
        <div>hello juejin</div>
        <p>hello world</p>
    </body>
</html>

Вначале синтаксический анализатор HTML создаст пустую структуру DOM, корнем которой является документ, поместит токен документа StartTag в стек, а затем поместит проанализированный первый HTML-код StartTag в стек и создаст html. Добавлен узел DOM. к документу.На данный момент стек токенов и дерево DOM выглядят следующим образом:

浏览器渲染原理-token1.png

Затем теги body и div будут помещены в стек так же, как и в предыдущем процессе:

浏览器渲染原理-token2.png

Затем текстовый токен в теге div будет проанализирован, и механизм рендеринга создаст текстовый узел для токена и добавит токен в DOM.Его родительский узел — это узел, соответствующий верхнему элементу текущего стека токенов:

浏览器渲染原理-token3.png

Далее следует первый элемент div EndTag. В это время синтаксический анализатор HTML определит, является ли текущий элемент в верхней части стека элементом div StartTag. Если это так, элемент div StartTag будет извлечен из вершины стека, как показано на следующий рисунок:

浏览器渲染原理-token4.png

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

浏览器渲染原理-token5.png

Во-вторых, построение дерева CSSOM

Вышеизложенное в основном поняло процесс построения DOM, но эта структура DOM содержит только узлы и не содержит никакой информации о стиле. Давайте посмотрим, как браузеры применяют стили CSS к узлам DOM.

Точно так же браузеры не могут напрямую понимать код CSS и должны преобразовывать дерево CSSOM, которое их браузеры могут понять. Фактически. Пока браузер строит дерево DOM, если стили также загружены, дерево CSSOM также будет построено синхронно. Дерево CSSOM похоже на дерево DOM и выполняет две основные функции:

  • Предоставляет возможность JavaScript управлять стилями;
  • Предоставляет базовую информацию о стилях для рендеринга компоновки дерева.

Однако дерево CSSOM и дерево DOM — это две независимые структуры данных, и между ними нет однозначного соответствия. Дерево DOM описывает иерархические отношения тегов HTML, а дерево CSSOM описывает иерархические отношения между селекторами. в консоли браузера черезdocument.styleSheetsКоманда для просмотра дерева CSSOM:image.pngКаковы источники стилей CSS?image.pngМы можем видеть исходный код CSS. Существует три основных стиля:

  • Внешний файл стилей CSS, на который ссылается ссылка;
  • <style>CSS-стили внутри тегов;
  • CSS, встроенный в атрибут стиля элемента.

Перед преобразованием CSS в древовидный объект также необходимо нормализовать значения свойств в таблице стилей, например, при встрече со следующими стилями CSS:

body { font-size: 2em }
p {color:blue;}
div {font-weight: bold}
div p {color:green;}
div {color:red; }

Вы можете видеть, что в приведенном выше CSS есть много значений атрибутов, таких как 2em, синий, красный, полужирный и т. д. Эти значения не понимаются браузером напрямую. Следовательно, необходимо преобразовать все значения в стандартизированные расчетные значения, которые легко понимаются механизмом рендеринга браузера.Этот процесс называется стандартизацией значений атрибутов. После процесса нормализации приведенный выше код станет таким:

body { font-size: 32px }
p {color: rgb(0, 0, 255);}
div {font-weight: 700}
div p {color: (0, 128, 0);}
div {color: (255, 0, 0); }

Как видите, 2em анализируется как 32px, синий — как rgb(255, 0, 0), а жирный — как 700. Теперь, когда атрибуты стиля стандартизированы, следующим шагом является вычисление атрибутов стиля каждого узла в дереве DOM, что включает в себя правила наследования CSS и правила каскадирования.

(1) Наследование стиля

В CSS есть механизм наследования стилей, наследование CSS заключается в том, что каждый узел DOM содержит стиль родительского узла. Например, если для HTML задано значение «размер шрифта: 20 пикселей», то практически все теги на странице могут наследовать это свойство.

В CSS в основном существуют следующие типы наследуемых свойств:

  1. Свойства семейства шрифтов
  • семейство шрифтов: семейство шрифтов
  • font-weight: вес шрифта
  • размер шрифта: размер шрифта
  • стиль шрифта: стиль шрифта
  1. Свойства текстовой серии
  • text-indent: отступ текста
  • text-align: горизонтальное выравнивание текста
  • высота строки: высота строки
  • word-spacing: расстояние между словами
  • letter-spacing: китайский или расстояние между буквами
  • text-transform: управлять регистром текста (то есть прописными, строчными, заглавными буквами этих трех)
  • цвет: цвет текста
  1. видимость элемента
  • видимость: управляет отображением и скрытием элемента.
  1. Список свойств макета
  • стиль списка: стиль списка, включая тип стиля списка, изображение стиля списка и т. д.
  1. свойства курсора
  • курсор: в какой форме отображается курсор

(2) Каскадирование стилей

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

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

Для следующего кода:

<html>
	<head>
		<link href="./style.css">
        <style>
            .juejin {
                width: 100px;
                height: 50px;
                background: red;
            }

            .content {
                font-size: 25px;
                line-height: 25px;
                margin: 10px;
            }
        </style>
	</head>
    <body>
        <div class="juejin">
    	    <div>CUGGZ</div>
        </div>
        <p style="color: blue" class="content">
            <span>hello world</span>
            <p style="display: none;">浏览器</p>
        </p>
    </body>
</html>

Окончательное сгенерированное дерево CSSOM выглядит примерно так:浏览器渲染原理-CSSOm.png

Три, построение дерева рендеринга

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

В разных браузерах процесс построения дерева рендеринга отличается:

  • В Chrome метод attach() используется на каждом узле, чтобы повесить узлы дерева CSSOM на дерево DOM в качестве дерева рендеринга.
  • В Firefox новая структура будет построена отдельно, чтобы связать отношения отображения между деревом DOM и деревом CSSOM.

Так зачем строить дерево рендеринга? Как вы можете видеть в приведенном выше примере, дерево DOM может содержать некоторые невидимые элементы, такие как теги заголовка, элементы с атрибутами display:none; и т. д. Поэтому перед отображением страницы необходимо построить дополнительное деревоДерево рендеринга, содержащее только видимые элементы.

Давайте посмотрим на процесс построения дерева рендеринга:浏览器渲染原理-第 7 页.pngКак видите, ни один из узлов, не видимых в дереве DOM, не включен в дерево рендеринга. Чтобы построить дерево рендеринга, браузер примерно выполняет следующую работу: просматривает все видимые узлы в дереве DOM и добавляет эти узлы в макет, а невидимые узлы будут игнорироваться деревом макета, например все содержимое ниже. тег head, другим примером является элемент pp, поскольку его атрибут содержит display:none, поэтому этот элемент не включается в дерево рендеринга. Если для элемента установлен атрибут visibility: hidden;, элемент появится в дереве рендеринга, потому что элементы с таким стилем должны занимать место, но их не нужно отображать. ​

В процессе поиска здесь для оперативности поиск будет начинаться с листового узла дерева CSSOM, который соответствует селектору CSS, то есть с крайней правой стороны селектора влево. Поэтому не рекомендуется использовать селекторы тегов и селекторы подстановочных знаков для определения стилей элементов. ​

Кроме того, один и тот же узел DOM может соответствовать нескольким узлам CSSOM, и какое правило CSS определяет конечный эффект, зависит от приоритета стиля. Когда элемент DOM управляется несколькими стилями, стили имеют следующий приоритет:Встроенные стили > Селектор идентификаторов > Селектор классов > Селектор тегов > Общий селектор > Унаследованные стили > Параметры браузера по умолчанию

Приоритет общих селекторов CSS следующий:

Селектор Формат приоритетный вес
селектор идентификатора #id 100
селектор класса .classname 10
селектор атрибутов а[ref="еее"] 10
Селектор псевдокласса li:last-child 10
Селектор тегов div 1
Селектор псевдоэлементов li:after 1
селектор соседнего брата h1+p 0
Подключ ul>li 0
селектор потомков li a 0
Селектор подстановочных знаков * 0

для селектораприоритет:

  • Селектор тегов, селектор псевдоэлементов: 1;
  • Селектор класса, селектор псевдо класса, селектор атрибута: 10;
  • селектор идентификатора: 100;
  • встроенный стиль: 1000;

Уведомление:

  • Стиль, объявленный !important, имеет наивысший приоритет;
  • Если приоритет тот же, применяется стиль, появившийся последним;
  • Унаследованные стили имеют самый низкий приоритет;

В-четвертых, макет страницы

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

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

浏览器渲染原理-第 8 页.png

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

Пять, рисунок страницы

1. Создайте слои

После макета доступны положение и размер каждого элемента, так что пора начинать рисовать страницу? Ответ — нет, потому что на странице может быть много сложных сцен, таких как изменение 3D, прокрутка страницы, сортировка по оси z с использованием z-индекса и т. д. Следовательно, для достижения этих эффектов механизм рендеринга также должен создавать выделенные узлы для определенных узлов.слойи создайте соответствующее дерево слоев.

Так что же такое слой? Я считаю, что друзья, которые использовали Photoshop, знакомы со слоями. Мы также можем выбрать вкладку «Слои» в инструментах разработчика браузера Chrome (если нет, вы можете найти ее в дополнительных инструментах), вы можете увидеть слои страницы, взяв в качестве примера домашнюю страницу Nuggets, ее слои следующим образом:image.pngВидно, что движок рендеринга делит страницу на множество слоев, и эти слои будут накладываться друг на друга в определенном порядке для формирования итоговой страницы. Здесь операция разбиения страницы на несколько слоев становитсяслоистый,Наконец, операция слияния этих слоев в один слой становитсясинтез,Слоирование и композит часто используются вместе. Chrome представил механизм слоирования и композиции для повышения эффективности рендеринга каждого рама.

Обычно не каждый узел в дереве рендеринга содержит слой.Если узел не имеет соответствующего слоя, узел будет принадлежать слою своего родительского узла. Итак, для какого узла движок браузера может создать новый слой? Необходимо выполнить одно из следующих условий:

(1) Элементы с атрибутами контекста наложения

Страница, которую мы видим, обычно представляет собой двухмерную плоскость, а контекст наложения может сделать страницу трехмерной. Эти HTML-элементы распределяются по оси Z перпендикулярно этой двумерной плоскости в соответствии с приоритетом их собственных атрибутов. Ниже приведены правила укладки для блочной модели:

На изображении выше сверху вниз расположены:

  • Фон и граница: устанавливает фон и границу текущего элемента контекста наложения.
  • Отрицательный z-индекс: Элементы с отрицательным атрибутом z-индекса в текущем контексте стека.
  • Поле блочного уровня: элементы-потомки не на встроенном уровне, не позиционированные в потоке документа.
  • Floating Box: плавающий элемент без позиционирования.
  • Inline Box: непозиционированные дочерние элементы встроенного уровня в потоке документа.
  • z-index: 0: позиционированные элементы с каскадным уровнем 0.
  • Положительный z-индекс: позиционированные элементы с положительным значением свойства z-индекса.

Уведомление:Когда элемент позиционируется с помощью z-index:auto, уровень сгенерированного блока в текущем контексте наложения равен 0, и новый контекст наложения не будет создан, если только он не является корневым элементом.

(2) Элементы, которые необходимо обрезать

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

2. Нарисуйте слои

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

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

浏览器渲染原理-绘制图层.png

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

В инструментах разработчика браузера Chrome вы можете увидеть список отрисовки и процесс отрисовки слоя через вкладку «Слой»:image.pngСписок рисования — это просто список, используемый для записи порядка рисования и инструкций по рисованию.Операции рисования выполняются потоком компоновки в механизме рендеринга.. Когда список отрисовки слоя готов, основной поток отправляет список отрисовки в поток компоновки.

Примечание. Операция композиции завершается в потоке композиции, поэтому выполнение операции композиции не повлияет на выполнение основного потока. ​

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

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

На этом весь процесс рендеринга завершен, и процесс можно резюмировать следующим образом:

  1. Встраивайте HTML-контент в дерево DOM;
  2. Встроить содержимое CSS в дерево CSSOM;
  3. Синтезировать дерево DOM и дерево CSSOM в дерево рендеринга;
  4. Разметка элементов страницы согласно дереву рендеринга;
  5. Выполнять иерархические операции над деревом рендеринга и генерировать иерархическое дерево;
  6. Создайте список рисунков для каждого слоя и отправьте его в поток компоновки;
  7. Поток компоновки делит слой на разные тайлы и преобразует тайлы в растровые изображения посредством растеризации;
  8. Поток композиции отправляет инструкции по рисованию плитки в процесс браузера;
  9. Процесс браузера генерирует страницу и отображает ее на экране.

6. Другие

1. Перекомпоновать и перекрасить

После разговора о процессе рендеринга движка браузера давайте рассмотрим два важных понятия: перекомпоновка и перерисовка. ​

Мы знаем, что дерево рендеринга строится динамически, поэтому изменения узлов DOM и CSS могут привести к перестроению дерева рендеринга. Изменения в дереве рендеринга приведут к перекомпоновке или перерисовке страницы. Давайте рассмотрим эти две концепции, а также условия, которые они вызывают, и действия, направленные на уменьшение триггера.

(1) перестановка

Когда наша операция вызывает изменение геометрического размера DOM-дерева (изменение размера, положения, компоновки и т. д. элемента), узлы, изменившиеся в дереве рендеринга, и узлы, на которые оно влияет, должны быть пересчитаны. Этот процесс называется перегруппировкой, также известной как оплавление. Когда происходит изменение, весь процесс рендеринга страницы приходится пересматривать заново, поэтому накладные расходы очень велики. ​

Следующие действия вызовут перекомпоновку страницы:

  • Страница отображается впервые;
  • Изменяется размер окна браузера;
  • Содержимое элемента меняется;
  • Изменяется размер или положение элемента;
  • Размер шрифта элемента меняется;
  • активировать псевдоклассы CSS;
  • Запрашивать определенные свойства или вызывать определенные методы;
  • Добавьте или удалите видимые элементы DOM.

Когда срабатывает перекомпоновка, поскольку браузер отображает страницу на основе макета потока, когда срабатывает перекомпоновка, окружающие элементы DOM будут переупорядочиваться.Это имеет два влияния:

  • Глобальная область действия: начиная с корневого узла, перекомпоновать все дерево рендеринга;
  • Локальная область: повторное размещение части дерева рендеринга или объекта рендеринга.
(2) Перерисовка

Когда модификация DOM вызывает изменение стиля, но не влияет на его геометрические свойства (такие как изменение цвета, цвета фона), браузеру не нужно пересчитывать геометрические свойства элемента, а сразу рисуется новый стиль. для элемента (пропустить перестановку) этот процесс называется перерисовкой. Проще говоря, перерисовка запускается модификациями свойств рисования элемента. ​

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

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

  • Цвет, свойства, связанные с фоном: background-color, background-image и т.д.;
  • свойства, связанные с контуром: цвет контура, ширина контура, оформление текста;
  • радиус границы, видимость, тень блока.

Уведомление:Когда запускается перекомпоновка, будет запущена перерисовка, но перерисовка не обязательно вызовет перекомпоновку.

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

  • Максимально используйте анимацию CSS3, которая может вызывать графический процессор для выполнения рендеринга.
  • При манипулировании DOM старайтесь работать с узлами DOM более низкого уровня.
  • Не используйтеtableмакет, небольшое изменение может сделать всеtableпереставлять
  • Выражения с использованием CSS
  • Не манипулируйте часто стилями элементов.Для статических страниц вы можете изменить имя класса, а не стиль.
  • Используйте absolute или fixed, чтобы элементы не попадали в поток документа, чтобы они не влияли на другие элементы при изменении.
  • Чтобы избежать частых манипуляций с DOM, вы можете создать фрагмент документаdocumentFragment, примените к нему все операции DOM и, наконец, добавьте его в документ
  • Сначала установите элементdisplay: none, и отображать его после завершения операции. Поскольку операции DOM над элементами со свойством display, равным none, не вызовут перекомпоновку и перерисовку.
  • Сгруппируйте несколько операций чтения (или записи) DOM вместе вместо операций чтения и записи, чередующихся с операциями записи. Это благодаряМеханизм очереди рендеринга в браузере.

Браузер оптимизирует себя для перекомпоновки и перерисовки страниц——очередь рендеринга,Браузер поставит все операции перекомпоновки и перерисовки в очередь.Когда операции в очереди достигнут определенного числа или определенного временного интервала, браузер группирует очередь. Это превратит несколько перекомпоновок и перерисовок в одну перерисовку перерисовки.

2. Влияние JavaScript на DOM

Наконец, давайте взглянем на влияние скриптов JavaScript на модель DOM. Когда синтаксический анализатор анализирует HTML, если он встречает

Взгляните на кусок кода:

<html>
    <body>
        <div>hello juejin</div>
        <script>
            document.getElementsByTagName('div')[0].innerText = 'juejin yyds'
        </script>
        <p>hello world</p>
    </body>
</html>

Здесь, после разбора тега div, будет проанализирован тег script.Структура DOM на данный момент выглядит следующим образом:

浏览器渲染原理-token6.png

В этот момент синтаксический анализатор HTML перестанет работать, а движок JavaScript начнет работать и выполнит содержимое скрипта в теге script. Поскольку этот скрипт изменяет содержимое первого div, после выполнения скрипта текст в div становится "juejin yyds". Когда скрипт выполняется, синтаксический анализатор HTML возобновляет процесс синтаксического анализа и продолжает синтаксический анализ следующего содержимого, пока генерируется окончательный DOM.

Сценарий JavaScript, о котором мы упоминали выше, напрямую встраивается в HTML с помощью тега script. Все усложняется, когда на странице появляется JavaScript. Например:

<html>
    <body>
        <div>hello juejin</div>
        <script type="text/javascript" src='./index.js'></script>
        <p>hello world</p>
    </body>
</html>

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

После приведенного выше анализа видно, что поток JavaScript будет блокировать парсинг DOM Мы можем ускорить загрузку скриптов JavaScript через CDN, сжатые скрипты и т. д. Если в файле скрипта нет соответствующего кода для управления DOM, вы можете настроить скрипт JavaScript на асинхронную загрузку и добавить атрибут async или defer в тег скрипта, чтобы реализовать асинхронную загрузку скрипта. Оба используются следующим образом:

<script async type="text/javascript" src='./index.js'></script>
<script defer type="text/javascript" src='./index.js'></script>

На следующем рисунке можно интуитивно увидеть разницу между асинхронной загрузкой и прямой загрузкой:image.pngСиний цвет представляет время загрузки скрипта JavaScript, красный — время выполнения скрипта JavaScript, а зеленый — анализ HTML.

Атрибуты defer и async используются для асинхронной загрузки внешних файлов JS-скриптов, и ни один из них не блокирует синтаксический анализ страницы., разница в следующем:

  • Порядок выполнения:Несколько тегов с атрибутом async не могут гарантировать порядок загрузки, несколько тегов с атрибутом defer выполняются в соответствии с порядком загрузки;
  • Выполняются ли сценарии параллельно:асинхронный атрибут, указывающийЗагрузка и выполнение последующих документов выполняется параллельно с загрузкой и выполнением js-скриптов, то есть асинхронное выполнение; атрибут defer, процесс загрузки последующих документов и загрузка js-скриптов (только загрузка и не выполнение в данный момент) осуществляются параллельно (асинхронно), JavaScript-скриптам нужно дождаться, пока все элементы документ анализируется перед выполнением, а событие DOMContentLoaded запускается перед выполнением.

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

<html>
    <head>
  	<style src='./style.css'></style>
    </head>
    <body>
        <div>hello juejin</div>
        <script>
            const ele = document.getElementsByTagName('div')[0];
            ele.innerText = 'juejin yyds';    // 操作DOM
            ele.style.color = 'skyblue';      // 操作CSSOM
        </script>
        <p>hello world</p>
    </body>
</html>

В приведенном выше коде строка 9 работает с DOM, а строка 10 — с CSSOM, поэтому перед выполнением скрипта JavaScript необходимо проанализировать все стили CSS над оператором JavaScript. Поэтому, если в коде есть ссылка на внешний файл CSS, перед выполнением JavaScript необходимо дождаться завершения загрузки внешнего файла CSS, и после разбора и создания объекта CSSOM сценарий JavaScript может быть выполнен. Прежде чем механизм JavaScript проанализирует JavaScript, он не знает, манипулирует ли JavaScript CSSOM, поэтому, когда механизм рендеринга сталкивается со сценарием JavaScript, независимо от того, манипулирует ли сценарий CSSOM, он загружает файл CSS, анализирует операцию и затем выполните сценарий JavaScript.

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

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

<html>
    <head>
        <style src='./style.css'></style>
    </head>
    <body>
        <div>hello juejin</div>
        <script type="text/javascript" src='./index.js'></script>
        <p>hello world</p>
    </body>
</html>

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

На этом статья заканчивается, если вы нашли ее полезной, ставьте лайк!

三连 .gif