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

Узнайте, как оптимизировать взаимодействие вашего веб-сайта с Next Paint.

Взаимодействие с следующей отрисовкой (INP) — это стабильная метрика Core Web Vital, которая оценивает общую реакцию страницы на взаимодействия с пользователем путем наблюдения за задержкой всех соответствующих взаимодействий , которые происходят на протяжении всего периода посещения пользователем страницы. Окончательное значение INP представляет собой самое продолжительное наблюдаемое взаимодействие (иногда без учета выбросов).

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

Хорошие значения INP составляют 200 миллисекунд или меньше, плохие значения — более 500 миллисекунд, а все, что находится между ними, требует улучшения.

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

Улучшение INP требует времени и усилий, но наградой становится лучший пользовательский опыт. В этом руководстве будет рассмотрен путь к улучшению INP.

Выясните, что является причиной плохого INP

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

Найдите медленные взаимодействия в полевых условиях

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

Если вы не полагаетесь на поставщика RUM для получения полевых данных, в руководстве по полевым данным INP рекомендуется использовать отчет об опыте пользователя Chrome (CrUX) через PageSpeed ​​Insights, чтобы заполнить пробелы. CrUX — это официальный набор данных программы Core Web Vitals, который предоставляет общую сводку показателей для миллионов веб-сайтов, включая INP. Однако CrUX часто не предоставляет контекстные данные, которые вы можете получить от поставщика RUM, чтобы помочь вам проанализировать проблемы. По этой причине мы по-прежнему рекомендуем сайтам использовать поставщика RUM, когда это возможно, или внедрять собственное решение RUM в дополнение к тому, что доступно в CrUX.

Диагностика медленных взаимодействий в лаборатории

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

Оптимизация взаимодействия

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

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

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

Выявите и уменьшите задержку ввода

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

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

Связь между оценкой сценария и длительными задачами во время запуска

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

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

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

Оптимизируйте обратные вызовы событий

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

Часто уступайте основному потоку

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

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

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

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

Выход, позволяющий выполнять работу по рендерингу быстрее

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

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

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

  1. Обновите текстовое поле, указав в нем то, что ввел пользователь, и примените необходимое форматирование.
  2. Обновите часть пользовательского интерфейса, которая отображает текущее количество слов.
  3. Запустите логику, чтобы проверить орфографические ошибки.
  4. Сохраните самые последние изменения (локально или в удаленной базе данных).

Код для этого может выглядеть примерно так:

textBox.addEventListener('input', (inputEvent) => {
  // Update the UI immediately, so the changes the user made
  // are visible as soon as the next frame is presented.
  updateTextBox(inputEvent);

  // Use `setTimeout` to defer all other work until at least the next
  // frame by queuing a task in a `requestAnimationFrame()` callback.
  requestAnimationFrame(() => {
    setTimeout(() => {
      const text = textBox.textContent;
      updateWordCount(text);
      checkSpelling(text);
      saveChanges(text);
    }, 0);
  });
});

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

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

Хотя использование setTimeout() внутри вызова requestAnimationFrame() в предыдущем примере кода, по общему признанию, немного эзотерично, это эффективный метод, который работает во всех браузерах и гарантирует, что некритичный код не блокирует следующий кадр.

Избегайте беспорядка в макете

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

Визуализация изменения макета, как показано на панели производительности Chrome DevTools.
Пример изменения макета, как показано на панели производительности Chrome DevTools. Задачи рендеринга, включающие изменение макета, будут отмечены красным треугольником в правом верхнем углу части стека вызовов, часто называемым «Пересчитать стиль» или «Макет» .

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

Минимизируйте задержку презентации

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

Минимизировать размер DOM

Если DOM страницы небольшой, работа по рендерингу обычно завершается быстро. Однако когда DOM становятся очень большими, работа по рендерингу имеет тенденцию масштабироваться с увеличением размера DOM. Зависимость между работой рендеринга и размером DOM не является линейной, но для рендеринга больших DOM требуется больше работы, чем для маленьких DOM. Большой DOM проблематичен в двух случаях:

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

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

Используйте content-visibility для ленивого рендеринга элементов за кадром.

Один из способов ограничить объем работы по рендерингу во время загрузки страницы и работы по рендерингу в ответ на взаимодействие с пользователем — это использовать свойство CSS content-visibility , которое фактически сводится к ленивому рендерингу элементов по мере их приближения к области просмотра. Хотя для эффективного использования content-visibility может потребоваться некоторая практика, стоит выяснить, сокращается ли в результате время рендеринга, что может улучшить INP вашей страницы.

Помните о затратах производительности при рендеринге HTML с использованием JavaScript.

Там, где есть HTML, есть анализ HTML, и после того, как браузер завершил анализ HTML в DOM, он должен применить к нему стили, выполнить вычисления макета и впоследствии отобразить этот макет. Это неизбежные затраты, но то, как вы выполняете рендеринг HTML, имеет значение.

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

Хотя первое посещение любого веб-сайта всегда включает в себя некоторый объем HTML, общий подход начинается с минимального начального фрагмента HTML, а затем для заполнения области содержимого используется JavaScript. Последующие обновления этой области содержимого также происходят в результате взаимодействия с пользователем. Обычно это называется моделью одностраничного приложения (SPA) . Одним из недостатков этого шаблона является то, что при рендеринге HTML с помощью JavaScript на клиенте вы не только получаете стоимость обработки JavaScript для создания этого HTML, но и браузер не уступит, пока не закончит анализ этого HTML и его рендеринг. .

Однако важно помнить, что даже веб-сайты, не являющиеся SPA, вероятно, будут включать в себя некоторый объем рендеринга HTML с помощью JavaScript в результате взаимодействия. В целом это нормально, если вы не отображаете на клиенте большие объемы HTML, что может задержать представление следующего кадра. Однако важно понимать, как этот подход к рендерингу HTML в браузере влияет на производительность и как он может повлиять на скорость реагирования вашего веб-сайта на ввод пользователя, если вы визуализируете большой объем HTML-кода с помощью JavaScript.

Заключение

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

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

Героическое изображение из Unsplash , созданное Дэвидом Писным и модифицированное в соответствии с лицензией Unsplash .