Среди веб-разработчиков растет понимание того, что скорость важна.
Многие стараются ускориться: используют gzip-сжатие, минификацию, кеширование заголовков, сокращение запросов, оптимизацию изображений и другие.
После выполнения этих рекомендаций возникает вопрос: что именно оптимизируем? Оказывается, в большинстве случаев именно столько времени требуется странице для полной загрузки всех элементов.
Однако это не совсем то, что нужно.
Что действительно важно, так это время, в течение которого пользователь получает «первый экран» страницы с важными функциональными элементами (заголовок, текст, описание товара и т. д.).
Другими словами, важен момент начала рендеринга страницы.
Здесь на помощь приходит критический путь рендеринга, который определяет все действия, которые браузер должен выполнить, чтобы начать рендеринг страницы.
Об этом мы и поговорим в статье.
Что такое критический путь?
Критический путь рендеринга – это набор минимальных действий, ресурсов и расчетов, необходимых для начала рисования страницы.Критический путь можно измерить с точки зрения количества критических ресурсов, минимального времени загрузки (измеряется в RTT) и объема критических ресурсов (в байтах).
Для иллюстрации возьмем самый простой пример: HTML-страницу размером 1 КБ без внешних ресурсов.
Критический путь будет следующим: 1 ресурс (HTML-документ), 1 RTT (минимум), 1 КБ трафика.
Однако такие простые страницы практически невозможно найти в природе, поэтому мы покажем, как можно определить критический путь на реальных веб-страницах.
Определение критического пути
Настоящая веб-страница состоит из HTML-документа и ряда внешних ресурсов: CSS-файлов, JS-файлов, шрифтов, изображений и т. д. Современные браузеры стараются максимально оптимизировать процесс загрузки страницы, чтобы как можно быстрее начать рендеринг..
Однако браузеры ограничены спецификациями CSS и JS, поэтому они должны создавать страницы в строгой последовательности.
Заключительный этап критического пути — построение Дерева рендеринга, по которому браузер может начать рендеринг.
Давайте рассмотрим основные этапы, которые включает в себя критический путь:
- Получите HTML-документ.
- Анализируйте HTML на наличие включенных ресурсов.
- Постройте дерево DOM (объектную модель документа).
- Отправьте запросы на критически важные элементы.
- Получите весь CSS-код (также запустите запросы для JS-файлов).
- Постройте дерево CSSOM.
- Выполните весь полученный JS-код.
- Перестройте дерево DOM (при необходимости).
- Постройте дерево рендеринга и начните рендеринг страницы.
Во-первых, в критическом пути участвуют ресурсы с CSS и JS-кодом.
Другие внешние ресурсы там не учитываются.
Во-вторых, код JS не может быть выполнен до тех пор, пока не будут получены все ресурсы CSS и не построено дерево CSSOM. В-третьих, страница не может быть отображена до выполнения кода JS, поскольку он может изменить дерево DOM. Но не все так просто: дело, как обычно, в деталях.
Наша цель — максимально сократить критический путь рендеринга нашей страницы.
Способы сокращения критического пути
Для примера возьмем код страницы из демо-версии плагина.Автозаполнение из пользовательского интерфейса jQuery.
Какие элементы составляют критический путь этой страницы?<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>jQuery UI Autocomplete - Default functionality</title> <link rel="stylesheet" href=" http://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css "> <script src=" http://code.jquery.com/jquery-1.10.2.js "></script> <script src=" http://code.jquery.com/ui/1.11.4/jquery-ui.js "></script> <link rel="stylesheet" href=" http://jqueryui.com/resources/demos/style.css "> <script> $(function() { var availableTags = [ "ActionScript", "AppleScript", "Scheme" ]; $( "#tags" ).
autocomplete({ source: availableTags }); }); </script> </head> <body> <div class="ui-widget"> <label for="tags">Tags: </label> <input id="tags"> </div> </body> </html>
- Сама страница (HTML).
- 2 CSS-файла.
- 2 JS-файла и JS-код в шапке страницы.
Сокращение критического пути рендеринга.
Что можно сделать в этом случае:
- Объедините два CSS в один файл.
- Объедините JS в один файл.
- Поместите вызов файла JS и встроенный код JS в конце страницы перед /body.
- Отложите загрузку CSS для элемента автозаполнения.
Поскольку светлое будущее (HTTP/2) не за горами, а SPDY – это уже настоящее, мы не будем заниматься слиянием файлов.
Давайте подробнее рассмотрим третью и четвертую оптимизации.
Перемещение вызова файла JS в конец документа позволит браузеру начать рендеринг страницы раньше.
Возможна ленивая загрузка CSS из пользовательского интерфейса jQuery, поскольку стили из этого файла нужны только для отображения элемента автозаполнения (после ввода в поле).
Вот как будет выглядеть конечная страница.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>jQuery UI Autocomplete - Default functionality</title>
<link rel="stylesheet" href=" http://jqueryui.com/resources/demos/style.css ">
</head>
<body>
<div class="ui-widget">
<label for="tags">Tags: </label>
<input id="tags">
</div>
<script>document.addEventListener("DOMContentLoaded", function(event) {
var availableTags = [
"ActionScript",
"AppleScript",
"Scheme"
];
$( "#tags" ).
autocomplete({ source: availableTags }); }); </script> <script>document.addEventListener("DOMContentLoaded", function(event) { $('head').
append('<link rel="stylesheet" href=" http://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css " type="text/css">');
});</script>
<script src=" http://code.jquery.com/jquery-1.10.2.js "></script>
<script src=" http://code.jquery.com/ui/1.11.4/jquery-ui.js "></script>
</body>
</html>
Обратите внимание: вызовы плагина jQuery UI заключены в следующую конструкцию: document.addEventListener("DOMContentLoaded", function(event) {
// plugin code
});
Это позволяет вам размещать код, зависящий от jQuery и его плагинов, в любом месте страницы.
Тот же метод используется для отложенной загрузки файла CSS. Теперь критический путь уменьшен на 1 запрос (CSS) и не требует загрузки (трафика) для начала рендеринга.
Переместив весь код JS в конец документа, браузер сможет начать рендеринг до выполнения кода.
Если на странице есть скрипты, которые можно выполнить позже (например, скрипты-счетчики, социальные плагины и т.п.
), то их можно удалить из критического пути отрисовки с помощью атрибута async: <script src=1.js async></script>
Однако с помощью jQuery и его плагинов этого сделать нельзя (есть способ асинхронной загрузки, но он довольно утомительный).
Поэтому воспользуемся решением, описанным выше.
Результат
Давайте проверим, что произошло.Загружаем оба файла в Chrome. Откройте инструменты разработчика, включите «Переключить режим устройства», ограничьте сеть до 450 Кбит/с 150 мс RT, загрузите без кеша.
При загрузке мы находимся на вкладке «Временная шкала».
Нас интересует момент начала рендеринга страницы (первые события Paint, они отображаются зеленым цветом).
Для неоптимизированной версии: 5000 мс, для оптимизированной версии 500 мс.
Используя описанные приемы, вы сможете значительно ускорить рендеринг своих страниц, особенно если они богаты функциональностью JS и содержат большое количество CSS-кода.
Делая оптимизацию, будьте осторожны: тестируйте каждое изменение — изменение порядка загрузки JS-библиотек может нарушить функциональность.
Что еще почитать
- Илья Григорик: Анализ производительности критического пути рендеринга
- Илья Григорик: измерение критического пути рендеринга с помощью времени навигации
-
Православные Активисты Хотят «Премии Рунета»
19 Oct, 24 -
Краткая История Развития Игровых Движков
19 Oct, 24