Если страница медленно реагирует на действия пользователя, у него может сложиться впечатление, что она работает неправильно или не работает вообще. Interaction to Next Paint (INP) – это показатель, основанный на Event Timing API. Для оценки скорости отклика страницы выбирается самое длительное взаимодействие (за вычетом некоторых выбросов).
Выявить основные причины, по которым веб-страница не отвечает, может быть непросто, особенно потому, что это зависит от взаимодействия с пользователем и условий окружающей среды, таких как возможности устройства и условия сети. Это делает диагностику ещё более сложной по сравнению с более повторяемым и предсказуемым сценарием, таким как загрузка страницы. Лабораторные данные отражают лишь небольшую часть реальных пользовательских сценариев, поэтому важно измерять причины медленного INP в полевых условиях.
Event Timing API позволяет разделить INP на три части: задержка ввода (обработка, которая уже происходит в момент взаимодействия), длительность обработки (задержки, вызванные непосредственно взаимодействием) и задержка отрисовки (задержки, вызванные отрисовкой следующего кадра после взаимодействия). Это помогает определить, где именно возникла проблема: в другом коде, в коде JavaScript, отвечающем за взаимодействие, или в обработке обновлений отрисовки браузером.
Можно получить дополнительную информацию о JavaScript, пересчете стилей и работе с макетом, задерживающих взаимодействие. Полная трассировка производительности с помощью JS Self-Profiling API – это ресурсоемкое решение, которое может привести к проблемам с производительностью. Long Animation Frames API – это легковесный API, который можно использовать в полевых условиях, чтобы выявлять медленно выполняющийся код JavaScript и различать пересчет стилей и затраты на макет во время взаимодействий INP.
- Принудительное изменение стиля и макета на уровне скрипта (
forcedStyleDurationиforcedLayoutDuration). Сообщает о синхронных перерасчетах стиля (например, вызовеgetComputedStyle()после изменений DOM) и принудительных изменениях макета/перекомпоновках (например, чтенииgetBoundingClientRect()илиoffsetWidthпосле изменений) в выполняющемся скрипте во время задержки ввода или длительности обработки. - Стиль и макет отрисовки на уровне кадра (
styleDurationиlayoutDuration). Показывает, сколько времени уходит на пересчет стилей и обновление макета при обновлении отрисовки кадра. Это помогает понять, почему возникает высокая задержка показа.
Различать пересчет стилей и макет критически важно, поскольку у них разные основные причины и способы устранения. Высокая продолжительность стиля указывает на дорогостоящее сопоставление селекторов CSS или широкую недействительность стиля (устраняется путем упрощения селекторов или уменьшения области действия правил), тогда как высокая продолжительность макета указывает на дорогостоящие геометрические вычисления или синхронную пробуксовку макета (устраняется путем пакетного чтения DOM перед записью, упрощения структуры DOM или использования CSS-контейнера).
Рекомендации по внедрению
Рассчитать INP на основе необработанных данных Event Timing API сложно, и здесь есть несколько нюансов. Для сбора этих данных рекомендуется использовать инструмент или библиотеку RUM.
web-vitals – это библиотека с открытым исходным кодом от Google, которая рассчитывает показатели Core Web Vitals, включая INP, а также содержит данные о подчастях и длительных кадрах анимации для взаимодействия INP.
Как получить атрибуты для взаимодействий INP с помощью библиотеки web-vitals
web-vitals – это небольшая библиотека, которая используется для измерения Core Web Vitals и других показателей эффективности. Функция onINP() позволяет определить самое медленное взаимодействие и получить информацию о подкомпонентах INP, скриптах, которые выполнялись во время взаимодействия, а также о длительности стилей и макетов с помощью Long Animation Frames API.
// Use the attribution build to get Long Animation Frame data
// alongside the INP metric value.
import { onINP } from 'web-vitals/attribution';
onINP((metric) => {
const { attribution } = metric;
const longestScript = attribution.longestScript;
// Sum rendering-phase style and layout durations across all LoAF entries
// intersecting the INP interaction (primarily explains presentationDelay).
let renderStyleDuration = 0;
let renderLayoutDuration = 0;
for (const entry of attribution.longAnimationFrameEntries) {
renderStyleDuration += entry.styleDuration ?? 0;
renderLayoutDuration += entry.layoutDuration ?? 0;
}
// Beacon script, style, and layout attribution for the INP interaction,
// so you can identify the root cause in production.
navigator.sendBeacon(
'/analytics',
JSON.stringify({
name: 'INP',
value: metric.value,
// These fields give the INP subparts:
inputDelay: attribution.inputDelay,
presentationDelay: attribution.presentationDelay,
processingDuration: attribution.processingDuration,
interactionTarget: attribution.interactionTarget,
// These fields identify which script function was responsible
// for the longest processing during the INP interaction.
invokerType: longestScript?.entry?.invokerType,
sourceURL: longestScript?.entry?.sourceURL,
sourceFunctionName: longestScript?.entry?.sourceFunctionName,
sourceCharPosition: longestScript?.entry?.sourceCharPosition,
// subpart indicates which phase (input delay, processing, or
// presentation delay) the longest script overlapped with most.
subpart: longestScript?.subpart,
intersectingDuration: longestScript?.intersectingDuration,
// Synchronous style and layout work forced inside the longest script
// (with forcedStyleAndLayoutDuration as a combined fallback):
forcedStyleDuration: longestScript?.entry?.forcedStyleDuration,
forcedLayoutDuration: longestScript?.entry?.forcedLayoutDuration,
forcedStyleAndLayoutDuration: longestScript?.entry?.forcedStyleAndLayoutDuration,
// Rendering-phase style and layout work across the interaction's frames
// (with totalStyleAndLayoutDuration as a combined fallback):
renderStyleDuration,
renderLayoutDuration,
totalStyleAndLayoutDuration: attribution.totalStyleAndLayoutDuration
})
);
});
Рекомендации
- РЕКОМЕНДУЕТСЯ использовать подкомпоненты INP, чтобы определить, чем вызвана задержка: уже выполняющимся кодом JavaScript (задержка ввода), обработчиками событий JavaScript для взаимодействия (длительность обработки) или последующей отрисовкой (задержка отображения).
- РЕКОМЕНДУЕТСЯ указывать в качестве дополнительной информации самый большой блокирующий код JavaScript, особенно для задержки ввода и длительности обработки.
- РЕКОМЕНДУЕТСЯ различать пересчет стилей (
styleDuration,forcedStyleDuration) и макет (layoutDuration,forcedLayoutDuration) при диагностике высокой продолжительности обработки или задержки представления. Высокое время обработки стилей указывает на ресурсоемкие селекторы CSS или широкие недействительности, а высокое время обработки макета указывает на узкие места в геометрии DOM или синхронное переполнение макета. - РЕКОМЕНДУЕТСЯ использовать Long Animation Frames API, чтобы получать более подробные данные, а не альтернативные решения, такие как JS Self-Profiling API, которые создают более высокую нагрузку на среду выполнения.
- ИСПОЛЬЗУЙТЕ библиотеку
web-vitals, если у вас нет другого решения для мониторинга реальных пользователей. Оно может идентифицировать взаимодействие INP и включает информацию о подчастях и скриптах, которые были выполнены во время взаимодействия (с использованием Long Animation Frames API). - РЕКОМЕНДУЕТСЯ передавать необходимую информацию в сервис аналитики, а не просто сохранять ее локально.
Поддержка браузеров и резервные стратегии
Event Timing API доступен в большинстве современных браузеров и необходим для расчета INP и его составляющих. В браузерах, которые не поддерживают этот API, измерить INP невозможно.
Long Animation Frames API предоставляет дополнительные сведения. Его можно использовать без резервных вариантов. В большинстве случаев возможности повышения производительности, которые он выявляет, будут применимы и к другим браузерам.
Если целевой набор Baseline поддерживает Long Animation Frames API (long-animation-frames), но не поддерживает отдельные свойства длительности стиля и макета (styleDuration и layoutDuration в PerformanceLongAnimationFrameTiming или forcedStyleDuration и forcedLayoutDuration в PerformanceScriptTiming), используйте комбинированные значения времени стиля и макета:
- Используйте
script.forcedStyleAndLayoutDurationна страницеPerformanceScriptTiming, чтобы синхронно принудительно применять стили и макеты в скриптах. - Используйте
metric.attribution.totalStyleAndLayoutDurationвweb-vitals/attribution(или вычисляйте(entry.paintTime || entry.startTime + entry.duration) - entry.styleAndLayoutStartдля каждой записиPerformanceLongAnimationFrameTiming), чтобы объединить работу со стилем и макетом.