Критический Путь Рендеринга Веб-Страниц

Среди веб-разработчиков растет понимание того, что скорость важна.

Многие стараются ускориться: используют gzip-сжатие, минификацию, кеширование заголовков, сокращение запросов, оптимизацию изображений и другие.

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

Однако это не совсем то, что нужно.

Что действительно важно, так это время, в течение которого пользователь получает «первый экран» страницы с важными функциональными элементами (заголовок, текст, описание товара и т. д.).

Другими словами, важен момент начала рендеринга страницы.

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

Об этом мы и поговорим в статье.



Что такое критический путь?

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

Критический путь можно измерить с точки зрения количества критических ресурсов, минимального времени загрузки (измеряется в RTT) и объема критических ресурсов (в байтах).

Для иллюстрации возьмем самый простой пример: HTML-страницу размером 1 КБ без внешних ресурсов.

Критический путь будет следующим: 1 ресурс (HTML-документ), 1 RTT (минимум), 1 КБ трафика.

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



Определение критического пути

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

.

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

Заключительный этап критического пути — построение Дерева рендеринга, по которому браузер может начать рендеринг.

Давайте рассмотрим основные этапы, которые включает в себя критический путь:

  1. Получите HTML-документ.
  2. Анализируйте HTML на наличие включенных ресурсов.

  3. Постройте дерево DOM (объектную модель документа).

  4. Отправьте запросы на критически важные элементы.

  5. Получите весь CSS-код (также запустите запросы для JS-файлов).

  6. Постройте дерево CSSOM.
  7. Выполните весь полученный JS-код.
  8. Перестройте дерево DOM (при необходимости).

  9. Постройте дерево рендеринга и начните рендеринг страницы.

Из этой последовательности можно сделать несколько важных выводов.

Во-первых, в критическом пути участвуют ресурсы с 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-код в шапке страницы.

При условии параллельной загрузки JS-файлов получаем 3 RTT (минимум).

Сокращение критического пути рендеринга.

Что можно сделать в этом случае:

  • Объедините два CSS в один файл.

  • Объедините JS в один файл.

  • Поместите вызов файла JS и встроенный код JS в конце страницы перед /body.
  • Отложите загрузку CSS для элемента автозаполнения.

Следует отметить, что первые две оптимизации актуальны только при использовании обычного HTTP без SPDY или HTTP/2, при котором количество запросов не имеет значения.

Поскольку светлое будущее (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-библиотек может нарушить функциональность.



Что еще почитать

Теги: #Оптимизация клиента #ускорение сайта #JavaScript #Разработка веб-сайтов #JavaScript #Оптимизация клиента
Вместе с данным постом часто просматривают: