Все знают, что прикладной слой всемирного интервета использует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>
когда выше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
Дерево, особой разницы в этом процессе нет.
Если вы хотите более подробно ознакомиться с построением критического пути рендеринга, вы можете использоватьChrome
в инструментах разработчика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
Скрипт также должен сначала дождаться сборкиCSSOM
Tree, ключевые характеристики пути рендеринга на приведенном выше рисунке следующие:
-
Ключевые ресурсы: 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 на сервер, и сервер проверяет токен в соответствии с текущим ресурсом (обычно ETag
Hash
После отпечатка), если ресурс не изменился, сервер вернет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">