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

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

[Определение] Критический путь отрисовки (CRP): последовательность шагов, которую выполняет браузер для преобразования HTML, CSS и JS в фактические пиксели на экране. Проще говоря, если это оптимизировать, веб-страницы будут работать быстрее.

В целях экономии места «оптимизация» в статье сокращается до «op».

[Этап 1] DOM: как только браузер получает данные с сервера, его токенизатор начинает синтаксический анализ HTML, создавая объектную модель документа.

[op 1] Отправить частичный HTML-код, чтобы начать создание веб-страницы, пока в фоновом режиме загружается больше данных.

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

[op 1] Добавьте встроенный CSS, чтобы удалить RTT запроса на выборку. Но это будет работать только для небольшого набора правил, так как огромный набор сделает HTML-файл тяжелее, и браузер в любом случае будет ждать, пока будет извлечен весь CSS, перед рендерингом, даже если вы разделите его по файлам!

[op 2] Добавьте медиа-запросы, чтобы точно сообщить браузеру, какой CSS требуется для отображения этой страницы. Медиа-запросы могут зависеть от размера экрана, ориентации или режима (просмотр / печать и т. Д.).

[Этап 1-2] JS: Javascript может создавать новые элементы DOM или изменять стили существующих. Следовательно, на основе кода JS парсер может многократно проходить этапы 1 и 2.

[op 1] Внешний JS - это блокировка парсера. Встроенный JS не блокирует построение DOM. Но встроенный JS может привести к избыточному коду на нескольких страницах.

[op 2] Добавление атрибута async в тег скрипта делает этот JS-файл неблокирующим.

Измерьте, прежде чем действовать! [Часть 1]

Кардинальное правило веб-производительности - сначала измерьте, а затем оптимизируйте

Когда дело доходит до оптимизации веб-приложений, не существует единого золотого правила. Сворачивание, сжатие и кеширование файлов всегда помогает, но это сильно зависит от того, как структурирован ваш проект. Ключ состоит в том, чтобы доставлять как можно меньше байтов, уменьшая критические ресурсы (которые могут быть синтаксическим анализатором или блокировкой рендеринга) и уменьшать длину CRP (количество циклов возврата, сделанных для получения всех критических ресурсов). Это так называемые показатели CRP. Прочтите эту отличную статью (5-минутное чтение), написанную Jesca, о том, как использовать инструменты разработчика Chrome (вкладка сети) для определения / измерения вышеуказанных показателей с примерами. .

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

[Этап 3] Дерево отрисовки: Дерево отрисовки захватывает только видимое содержимое. Он объединяет DOM и CSSOM и получает реальное представление того, что мы увидим на экране.

[op 1] Скрыть элементы, которые не видны в определенном фрейме, с помощью свойства CSS display, установленного на none, вместо установки свойства opacity на нуль.

[op 2] По возможности удалите все ненужные элементы DOM.

[Этап 4] Макет: этап макета определяет, где и как элементы расположены на экране.

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

[Этап 5] Рисование. На этапе рисования браузер рисует пиксели. Он разделяет всю страницу на слои, чтобы минимизировать область рисования при обновлениях.

[op 1] Хотя мы не можем управлять созданием слоя, мы можем указать свойство CSS will-change для элементов, чтобы сообщить Chrome / Firefox, что эти элементы должны часто меняться, чтобы они могли улучшаться. решения при наслоении.

Примечание автора 3: Оптимизация, обсуждаемая до сих пор, поможет вам получить быстрые статические веб-страницы с очень небольшим количеством циклов CRP. Когда веб-приложение включает в себя анимацию, исследование показывает, что 60 FPS - хорошая цель для обеспечения работы без дрожания. Таким образом, браузер имеет примерно 1000/60 = 16 мс. рисовать каждый кадр!

Измерьте, прежде чем действовать! [Часть 2]

Кардинальное правило веб-производительности - сначала измерьте, а затем оптимизируйте

[Определение] Цикл рендеринга: последовательность шагов, которые браузер выполняет при рендеринге кадра анимации. При необходимости он включает 1 или несколько циклов CRP.

Выполнить кадр анимации запускает JS, необходимый для добавления новых элементов DOM или обновления существующих, чтобы отразить следующий шаг анимации. Браузер обновляет DOM и CSSOM соответственно и создает дерево рендеринга в стилях пересчета. Затем layout step вычисляет макеты и обновляет дерево слоев. Выполняется рисование реальных пикселей на различных слоях, и, наконец, этап составной слой управляет слоями на экране.

Мера…

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

Примечание автора 4: Вы можете сохранить / загрузить любую графику временной шкалы в браузер для анализа из контекстного меню вкладки временной шкалы! Я продолжу объяснение с помощью временной шкалы трассировки 2D-анимации (блоков) из одного из моих демонстрационных проектов.

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

Щелчок по рамке открывает внизу еще одно окно с различными вкладками. В то время как вид диаграммы пламени дает общую картину, в журнале событий отображается точное время, затраченное на каждый шаг. В случае шагов JS вы можете открыть, чтобы увидеть, какие функции и сколько времени выполнялись. Расширение шагов пересчета стиля покажет запросы на выборку медиаресурсов, отправленных во время рендеринга (если есть).

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

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

  • Как только вы поймете узкие места JS из журнала событий, вы можете использовать веб-воркеров, чтобы иметь только JS, необходимый для рендеринга в потоке, блокирующем парсер.
  • Используйте requestAnimationFrame для запуска функции, необходимой для анимации, вместо setTimeout или setInterval. Это позволяет браузеру выбрать подходящее время для запуска следующего цикла анимации, когда конвейер рендеринга не является тяжелым.
  • Некоторые шаги пропускаются браузером в зависимости от того, какие свойства были обновлены в дереве визуализации. Например, обновление связанных с геометрией свойств CSS, таких как ширина, позиция, запускает шаг макета. Если свойства, такие как цвет фона, непрозрачность обновляются, макет не запускается. Свойство преобразования пропускает этапы макета и рисования. Csstriggers дает исчерпывающий список шагов, запускаемых при каждом изменении свойства.
  • Избегайте принудительной синхронной компоновки. Рассмотрим следующий код:
var paragraphs = document.querySelector('p');
var greenBlock = document.getElementById('block');
for(var p = 0; p < paragraphs.length; p++){
    var blockWidth = greenBlock.offsetWidth;
    paragraphs[p].style.width = blockwidth + 'px';
}

Когда вы получаете доступ к offsetWidth элемента в JS, браузер должен рассчитать макеты, чтобы получить его. И когда вы меняете стиль, макет вызывается снова. Итак, в приведенном выше коде каждый цикл for стоит 2 макета! Это увеличит длину цикла рендеринга, снизив частоту кадров. Любое свойство, для которого браузер должен запускать макет, например геометрические свойства, может вызвать FSL.

Примечание автора 5: не существует единого способа оптимизировать веб-приложение. Это сильно зависит от вашего проекта. Сначала измерьте, чтобы найти узкие места и соответствующим образом оптимизировать.