Узнайте, как находить медленные взаимодействия в полевых данных вашего веб-сайта, чтобы найти возможности улучшить взаимодействие с Next Paint.
Данные полей — это данные, которые говорят вам, как реальные пользователи взаимодействуют с вашим веб-сайтом. Он выявляет проблемы, которые невозможно найти только в лабораторных данных . Что касается взаимодействия с следующей отрисовкой (INP) , полевые данные необходимы для выявления медленных взаимодействий и предоставляют важные подсказки, которые помогут вам их исправить.
В этом руководстве вы узнаете, как быстро оценить INP вашего веб-сайта, используя полевые данные из отчета об опыте пользователей Chrome (CrUX), чтобы определить, есть ли на вашем веб-сайте проблемы с INP. Впоследствии вы узнаете, как использовать сборку атрибуции библиотеки JavaScript web-vitals — и новые идеи, которые она предоставляет из API длинных анимационных кадров (LoAF) — для сбора и интерпретации данных полей для медленного взаимодействия на вашем веб-сайте.
Начните с CrUX, чтобы оценить INP вашего сайта.
Если вы не собираете полевые данные от пользователей вашего веб-сайта, CrUX может стать хорошей отправной точкой. CrUX собирает полевые данные от реальных пользователей Chrome, которые согласились отправлять данные телеметрии.
Данные CrUX появляются в различных областях, и это зависит от объема информации, которую вы ищете. CrUX может предоставить данные об INP и других основных веб-показателях для:
- Отдельные страницы и целые источники с использованием PageSpeed Insights .
- Типы страниц. Например, многие веб-сайты электронной коммерции имеют типы «Страница сведений о продукте» и «Страница со списком продуктов». Вы можете получить данные CrUX для уникальных типов страниц в Search Console .
В качестве отправной точки вы можете ввести URL-адрес своего веб-сайта в PageSpeed Insights. После ввода URL-адреса данные полей для него (если они доступны) будут отображаться для нескольких показателей, включая INP. Вы также можете использовать переключатели, чтобы проверить значения INP для размеров мобильных устройств и настольных компьютеров.

Эти данные полезны, поскольку они сообщают вам, есть ли у вас проблемы. Однако CrUX не может сказать вам, что вызывает проблемы. Существует множество доступных решений для мониторинга реальных пользователей (RUM), которые помогут вам собрать собственные данные полей от пользователей вашего веб-сайта, чтобы помочь вам ответить на этот вопрос, и один из вариантов — собрать эти данные полей самостоятельно с помощью библиотеки JavaScript web-vitals.
Собирайте полевые данные с помощью библиотеки JavaScript web-vitals
Библиотека JavaScript web-vitals
— это скрипт, который вы можете загрузить на свой веб-сайт для сбора данных о полях от пользователей вашего веб-сайта. Вы можете использовать его для записи ряда показателей, включая INP в браузерах, которые его поддерживают.
Стандартную сборку библиотеки web-vitals можно использовать для получения основных данных INP от пользователей в полевых условиях:
import {onINP} from 'web-vitals';
onINP(({name, value, rating}) => {
console.log(name); // 'INP'
console.log(value); // 512
console.log(rating); // 'poor'
});
Чтобы проанализировать данные полей от ваших пользователей, вам нужно отправить эти данные куда-нибудь:
import {onINP} from 'web-vitals';
onINP(({name, value, rating}) => {
// Prepare JSON to be sent for collection. Note that
// you can add anything else you'd want to collect here:
const body = JSON.stringify({name, value, rating});
// Use `sendBeacon` to send data to an analytics endpoint.
// For Google Analytics, see https://github.com/GoogleChrome/web-vitals#send-the-results-to-google-analytics.
navigator.sendBeacon('/analytics', body);
});
Однако сами по себе эти данные не скажут вам гораздо больше, чем мог бы рассказать CrUX. Вот тут-то и пригодится сборка атрибуции библиотеки web-vitals.
Идите дальше со сборкой атрибуции библиотеки Web-Vitals.
Сборка атрибуции библиотеки веб-показателей предоставляет дополнительные данные, которые вы можете получить от пользователей на местах, чтобы помочь вам лучше устранять проблемные взаимодействия, влияющие на INP вашего веб-сайта. Эти данные доступны через объект attribution
, представленный в методе библиотеки onINP()
:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, rating, attribution}) => {
console.log(name); // 'INP'
console.log(value); // 56
console.log(rating); // 'good'
console.log(attribution); // Attribution data object
});

Помимо самого INP страницы, сборка атрибуции предоставляет множество данных, которые вы можете использовать, чтобы понять причины медленного взаимодействия, включая то, на какой части взаимодействия вам следует сосредоточиться. Это поможет вам ответить на такие важные вопросы, как:
- «Взаимодействовал ли пользователь со страницей во время ее загрузки?»
- «Длительно ли работали обработчики событий взаимодействия?»
- «Был ли задержан запуск кода обработчика событий взаимодействия? Если да, что еще происходило в основном потоке в это время?»
- «Вызвало ли это взаимодействие большую работу по рендерингу, которая задержала прорисовку следующего кадра?»
В следующей таблице показаны некоторые основные данные атрибуции, которые вы можете получить из библиотеки и которые помогут вам выяснить некоторые общие причины медленного взаимодействия на вашем веб-сайте:
ключ объекта attribution | Данные |
---|---|
interactionTarget | Селектор CSS, указывающий на элемент, создавший значение INP страницы, например button#save . |
interactionType | Тип взаимодействия: щелчки, касания или ввод с клавиатуры. |
inputDelay * | Задержка ввода взаимодействия. |
processingDuration * | Время с момента запуска первого прослушивателя событий в ответ на взаимодействие с пользователем до завершения всей обработки прослушивателя событий. |
presentationDelay * | Задержка представления взаимодействия, которая происходит с момента завершения обработчиков событий до момента рисования следующего кадра. |
longAnimationFrameEntries * | Записи из LoAF, связанные с взаимодействием. Дополнительную информацию смотрите далее. |
Начиная с версии 4 библиотеки web-vitals, вы можете получить еще более глубокое понимание проблемных взаимодействий с помощью данных, которые она предоставляет с разбивкой по фазам INP (задержка ввода, продолжительность обработки и задержка представления) и API длинных анимационных кадров (LoAF) .
API длинных кадров анимации (LoAF)
Отладка взаимодействий с использованием полевых данных — сложная задача. Однако с помощью данных LoAF теперь можно лучше понять причины медленного взаимодействия, поскольку LoAF предоставляет ряд подробных таймингов и других данных, которые вы можете использовать для точного определения точных причин — и, что более важно, того, где находится источник проблемы в коде вашего веб-сайта.
Сборка атрибуции библиотеки web-vitals предоставляет массив записей LoAF под ключом longAnimationFrameEntries
объекта attribution
. В следующей таблице перечислены несколько ключевых битов данных, которые вы можете найти в каждой записи LoAF:
Ключ объекта входа LoAF | Данные |
---|---|
duration | Продолжительность длинного кадра анимации до завершения макета, но исключая рисование и композицию. |
blockingDuration | Общее количество времени в кадре, в течение которого браузер не мог быстро отреагировать из-за длительных задач. Это время блокировки может включать в себя длительные задачи, выполняющие JavaScript, а также любые последующие длительные задачи рендеринга в кадре. |
firstUIEventTimestamp | Временная метка того, когда событие было поставлено в очередь во время кадра. Полезно для определения начала задержки ввода взаимодействия. |
startTime | Начальная временная метка кадра. |
renderStart | Когда началась работа по рендерингу кадра. Сюда входят любые обратные вызовы requestAnimationFrame (и обратные вызовы ResizeObserver , если применимо), но, возможно, до начала какой-либо работы со стилем/макетом. |
styleAndLayoutStart | Когда происходит работа над стилем/макетом в кадре. Может быть полезно при определении продолжительности работы над стилем/макетом при определении других доступных временных меток. |
scripts | Массив элементов, содержащих информацию об атрибуции сценария, вносящую вклад в INP страницы. |

blockingDuration
). Вся эта информация может многое рассказать вам о том, что замедляет взаимодействие, но особый интерес должен представлять массив scripts
, отображаемый в записях LoAF:
Ключ объекта атрибуции скрипта | Данные |
---|---|
invoker | Вызывающий. Это может варьироваться в зависимости от типа инициатора, описанного в следующей строке. Примерами инициаторов могут быть такие значения, как 'IMG#id.onload' , 'Window.requestAnimationFrame' или 'Response.json.then' . |
invokerType | Тип вызывающего. Может быть 'user-callback' , 'event-listener' , 'resolve-promise' , 'reject-promise' , 'classic-script' или 'module-script' . |
sourceURL | URL-адрес сценария, из которого был создан длинный кадр анимации. |
sourceCharPosition | Позиция символа в скрипте, определяемая sourceURL . |
sourceFunctionName | Имя функции в идентифицированном скрипте. |
Каждая запись в этом массиве содержит данные, показанные в этой таблице, которые дают вам информацию о сценарии, который был ответственен за медленное взаимодействие, и о том, как он виноват.
Измерьте и определите общие причины медленного взаимодействия
Чтобы дать вам представление о том, как вы можете использовать эту информацию, в этом руководстве будет описано, как вы можете использовать данные LoAF, представленные в библиотеке web-vitals
для определения некоторых причин медленного взаимодействия.
Длительная продолжительность обработки
Продолжительность обработки взаимодействия — это время, необходимое для завершения зарегистрированных обратных вызовов обработчика событий взаимодействия и всего остального, что может произойти между ними. О высокой продолжительности обработки свидетельствует библиотека веб-виталов:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {processingDuration} = attribution; // 512.5
});
Естественно думать, что основной причиной медленного взаимодействия является то, что код обработчика событий выполнялся слишком долго, но это не всегда так! Как только вы подтвердите, что это проблема, вы можете копнуть глубже с данными LoAF:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {processingDuration} = attribution; // 512.5
// Get the longest script from LoAF covering `processingDuration`:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
if (script) {
// Get attribution for the long-running event handler:
const {invokerType} = script; // 'event-listener'
const {invoker} = script; // 'BUTTON#update.onclick'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Как видно из предыдущего фрагмента кода, вы можете работать с данными LoAF, чтобы отслеживать точную причину взаимодействия со значениями высокой продолжительности обработки, включая:
- Элемент и его зарегистрированный прослушиватель событий.
- Файл сценария (и позиция символа в нем), содержащий код обработчика долговременных событий.
- Имя функции.
Этот тип данных бесценен. Вам больше не нужно утомлять себя поиском того, какое именно взаимодействие (или какой из его обработчиков событий) отвечает за высокие значения длительности обработки. Кроме того, поскольку сторонние сценарии часто могут регистрировать свои собственные обработчики событий, вы можете определить, виноват ли в этом ваш код! Для кода, который вы контролируете, вам следует изучить возможность оптимизации длинных задач .
Длительные задержки ввода
Хотя обработчики событий с длительным выполнением являются обычным явлением, существуют и другие части взаимодействия, которые следует учитывать. Одна часть происходит до начала обработки, которая называется входной задержкой . Это время с момента, когда пользователь инициирует взаимодействие, до момента, когда начинают выполняться обратные вызовы его обработчика событий, и это происходит, когда основной поток уже обрабатывает другую задачу. Сборка атрибуции библиотеки web-vitals может сообщить вам продолжительность задержки ввода для взаимодействия:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
});
Если вы заметили, что некоторые взаимодействия имеют большие задержки ввода, вам нужно будет выяснить, что происходило на странице в момент взаимодействия, вызвавшего длительную задержку ввода — и это часто сводится к тому, произошло ли взаимодействие во время загрузки страницы или после нее.
Это было во время загрузки страницы?
Основной поток часто бывает наиболее загружен во время загрузки страницы. В это время всевозможные задачи ставятся в очередь и обрабатываются, и если пользователь попытается взаимодействовать со страницей во время всей этой работы, это может задержать взаимодействие. Страницы, загружающие много JavaScript, могут запускать работу по компиляции и оценке сценариев, а также выполнять функции, которые подготавливают страницу к взаимодействию с пользователем. Эта работа может помешать, если пользователь взаимодействует во время этого действия, и вы можете выяснить, так ли это для пользователей вашего веб-сайта:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
// Get the longest script from the first LoAF entry:
const loaf = attribution.longAnimationFrameEntries[0];
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
if (script) {
// Invoker types can describe if script eval blocked the main thread:
const {invokerType} = script; // 'classic-script' | 'module-script'
const {sourceLocation} = script; // 'https://example.com/app.js'
}
});
Если вы записываете эти данные в поле и видите большие задержки ввода и типы активаторов 'classic-script'
или 'module-script'
, то справедливо будет сказать, что сценарии на вашем сайте требуют много времени для оценки и блокируют основной поток достаточно долго, чтобы задержать взаимодействие. Вы можете сократить время блокировки, разбив свои скрипты на более мелкие пакеты, отложив загрузку изначально неиспользуемого кода на более поздний момент и проверив свой сайт на наличие неиспользуемого кода, который можно полностью удалить.
Это было после загрузки страницы?
Хотя задержки ввода часто возникают во время загрузки страницы, вполне возможно, что они могут возникнуть и после загрузки страницы по совершенно другой причине. Распространенными причинами задержек ввода после загрузки страницы может быть код, который периодически выполняется из-за более раннего вызова setInterval
, или даже обратные вызовы событий, которые были поставлены в очередь для запуска ранее и все еще обрабатываются.
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
// Get the longest script from the first LoAF entry:
const loaf = attribution.longAnimationFrameEntries[0];
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
if (script) {
const {invokerType} = script; // 'user-callback'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Как и в случае с устранением неполадок с высокими значениями длительности обработки, высокие задержки ввода по причинам, упомянутым ранее, предоставят вам подробные данные об атрибуции сценария. Однако отличие заключается в том, что тип инициатора будет меняться в зависимости от характера работы, которая задержала взаимодействие:
-
'user-callback'
указывает, что задача блокировки была изsetInterval
,setTimeout
или дажеrequestAnimationFrame
. -
'event-listener'
указывает, что задача блокировки была взята из более раннего ввода, который был поставлен в очередь и все еще обрабатывается. -
'resolve-promise'
и'reject-promise'
означают, что задача блокировки возникла в результате какой-то асинхронной работы, которая была запущена ранее и решена или отклонена в тот момент, когда пользователь пытался взаимодействовать со страницей, задерживая взаимодействие.
В любом случае данные об атрибуции скрипта дадут вам представление о том, с чего начать поиск и была ли задержка ввода вызвана вашим собственным кодом или кодом стороннего скрипта.
Длительные задержки презентации
Задержки представления — это последняя миля взаимодействия, они начинаются, когда завершаются обработчики событий взаимодействия, вплоть до момента рисования следующего кадра. Они возникают, когда работа в обработчике событий вследствие взаимодействия меняет визуальное состояние пользовательского интерфейса. Как и в случае с длительностью обработки и задержками ввода, библиотека веб-виталов может сообщить вам, как долго длилась задержка презентации для взаимодействия:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 113.32307691
});
Если вы записываете эти данные и видите высокие задержки представления взаимодействий, способствующих INP вашего веб-сайта, виновники могут быть разными, но вот несколько причин, на которые следует обратить внимание.
Дорогая стилистика и верстка.
Длительные задержки представления могут быть дорогостоящими пересчетами стилей и работой по макету , что возникает по ряду причин, включая сложные селекторы CSS и большие размеры DOM . Вы можете измерить продолжительность этой работы с помощью таймингов LoAF, доступных в библиотеке веб-виталов:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 113.32307691
// Get the longest script from the last LoAF entry:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
// Get necessary timings:
const {startTime} = loaf; // 2120.5
const {duration} = loaf; // 1002
// Figure out the ending timestamp of the frame (approximate):
const endTime = startTime + duration; // 3122.5
// Get the start timestamp of the frame's style/layout work:
const {styleAndLayoutStart} = loaf; // 3011.17692309
// Calculate the total style/layout duration:
const styleLayoutDuration = endTime - styleAndLayoutStart; // 111.32307691
if (script) {
// Get attribution for the event handler that triggered
// the long-running style and layout operation:
const {invokerType} = script; // 'event-listener'
const {invoker} = script; // 'BUTTON#update.onclick'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
LoAF не сообщит вам продолжительность работы над стилем и макетом для кадра, но сообщит, когда она началась. С помощью этой начальной временной метки вы можете использовать другие данные из LoAF для расчета точной продолжительности этой работы, определяя время окончания кадра и вычитая из нее временную метку начала работы над стилем и макетом.
Длительные обратные вызовы requestAnimationFrame
Одной из потенциальных причин длительных задержек представления является чрезмерная работа, выполняемая при обратном вызове requestAnimationFrame
. Содержимое этого обратного вызова выполняется после завершения работы обработчиков событий, но непосредственно перед перерасчетом стиля и работой с макетом.
Выполнение этих обратных вызовов может занять значительное время, если выполняемая в них работа сложна. Если вы подозреваете, что высокие значения задержки представления связаны с работой, которую вы выполняете с requestAnimationFrame
, вы можете использовать данные LoAF, полученные библиотекой web-vitals, для идентификации этих сценариев:
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 543.1999999880791
// Get the longest script from the last LoAF entry:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
// Get the render start time and when style and layout began:
const {renderStart} = loaf; // 2489
const {styleAndLayoutStart} = loaf; // 2989.5999999940395
// Calculate the `requestAnimationFrame` callback's duration:
const rafDuration = styleAndLayoutStart - renderStart; // 500.59999999403954
if (script) {
// Get attribution for the event handler that triggered
// the long-running requestAnimationFrame callback:
const {invokerType} = script; // 'user-callback'
const {invoker} = script; // 'FrameRequestCallback'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Если вы видите, что значительная часть времени задержки представления тратится на обратный вызов requestAnimationFrame
, убедитесь, что работа, которую вы выполняете в этих обратных вызовах, ограничивается выполнением работы, которая приводит к фактическому обновлению пользовательского интерфейса. Любая другая работа, которая не затрагивает DOM или стили обновления, приведет к неоправданной задержке рисования следующего кадра, поэтому будьте осторожны!
Заключение
Полевые данные — лучший источник информации, который вы можете использовать, когда дело доходит до понимания того, какие взаимодействия являются проблематичными для реальных пользователей в полевых условиях. Полагаясь на инструменты сбора полевых данных, такие как библиотека JavaScript web-vitals (или поставщик RUM), вы можете быть более уверены в том, какие взаимодействия являются наиболее проблематичными, а затем перейти к воспроизведению проблемных взаимодействий в лаборатории , а затем приступить к их исправлению.
Героическое изображение из Unsplash , автор Федерико Респини .
,Узнайте, как находить медленные взаимодействия в полевых данных вашего веб-сайта, чтобы найти возможности улучшить взаимодействие с Next Paint.
Данные полей — это данные, которые говорят вам, как реальные пользователи взаимодействуют с вашим веб-сайтом. Он выявляет проблемы, которые невозможно найти только в лабораторных данных . Что касается взаимодействия с следующей отрисовкой (INP) , полевые данные необходимы для выявления медленных взаимодействий и предоставляют важные подсказки, которые помогут вам их исправить.
В этом руководстве вы узнаете, как быстро оценить INP вашего веб-сайта, используя полевые данные из отчета об опыте пользователей Chrome (CrUX), чтобы определить, есть ли на вашем веб-сайте проблемы с INP. Впоследствии вы узнаете, как использовать сборку атрибуции библиотеки JavaScript web-vitals — и новые идеи, которые она предоставляет из API длинных анимационных кадров (LoAF) — для сбора и интерпретации данных полей для медленного взаимодействия на вашем веб-сайте.
Начните с CrUX, чтобы оценить INP вашего сайта.
Если вы не собираете полевые данные от пользователей вашего веб-сайта, CrUX может стать хорошей отправной точкой. CrUX собирает полевые данные от реальных пользователей Chrome, которые согласились отправлять данные телеметрии.
Данные CrUX появляются в различных областях, и это зависит от объема информации, которую вы ищете. CrUX может предоставить данные об INP и других основных веб-показателях для:
- Отдельные страницы и целые источники с использованием PageSpeed Insights .
- Типы страниц. Например, многие веб-сайты электронной коммерции имеют типы «Страница сведений о продукте» и «Страница со списком продуктов». Вы можете получить данные CrUX для уникальных типов страниц в Search Console .
В качестве отправной точки вы можете ввести URL-адрес своего веб-сайта в PageSpeed Insights. После ввода URL-адреса данные полей для него (если они доступны) будут отображаться для нескольких показателей, включая INP. Вы также можете использовать переключатели, чтобы проверить значения INP для размеров мобильных устройств и настольных компьютеров.

Эти данные полезны, поскольку они сообщают вам, есть ли у вас проблемы. Однако CrUX не может сказать вам, что вызывает проблемы. Существует множество доступных решений для мониторинга реальных пользователей (RUM), которые помогут вам собрать собственные данные полей от пользователей вашего веб-сайта, чтобы помочь вам ответить на этот вопрос, и один из вариантов — собрать эти данные полей самостоятельно с помощью библиотеки JavaScript web-vitals.
Собирайте полевые данные с помощью библиотеки JavaScript web-vitals
Библиотека JavaScript web-vitals
— это скрипт, который вы можете загрузить на свой веб-сайт для сбора данных о полях от пользователей вашего веб-сайта. Вы можете использовать его для записи ряда показателей, включая INP в браузерах, которые его поддерживают.
Стандартную сборку библиотеки web-vitals можно использовать для получения основных данных INP от пользователей в полевых условиях:
import {onINP} from 'web-vitals';
onINP(({name, value, rating}) => {
console.log(name); // 'INP'
console.log(value); // 512
console.log(rating); // 'poor'
});
Чтобы проанализировать данные полей от ваших пользователей, вам нужно отправить эти данные куда-нибудь:
import {onINP} from 'web-vitals';
onINP(({name, value, rating}) => {
// Prepare JSON to be sent for collection. Note that
// you can add anything else you'd want to collect here:
const body = JSON.stringify({name, value, rating});
// Use `sendBeacon` to send data to an analytics endpoint.
// For Google Analytics, see https://github.com/GoogleChrome/web-vitals#send-the-results-to-google-analytics.
navigator.sendBeacon('/analytics', body);
});
Однако сами по себе эти данные не скажут вам гораздо больше, чем мог бы рассказать CrUX. Вот тут-то и пригодится сборка атрибуции библиотеки web-vitals.
Идите дальше со сборкой атрибуции библиотеки Web-Vitals.
Сборка атрибуции библиотеки веб-показателей предоставляет дополнительные данные, которые вы можете получить от пользователей на местах, чтобы помочь вам лучше устранять проблемные взаимодействия, влияющие на INP вашего веб-сайта. Эти данные доступны через объект attribution
, представленный в методе библиотеки onINP()
:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, rating, attribution}) => {
console.log(name); // 'INP'
console.log(value); // 56
console.log(rating); // 'good'
console.log(attribution); // Attribution data object
});

Помимо самого INP страницы, сборка атрибуции предоставляет множество данных, которые вы можете использовать, чтобы понять причины медленного взаимодействия, включая то, на какой части взаимодействия вам следует сосредоточиться. Это поможет вам ответить на такие важные вопросы, как:
- «Взаимодействовал ли пользователь со страницей во время ее загрузки?»
- «Длительно ли работали обработчики событий взаимодействия?»
- «Был ли задержан запуск кода обработчика событий взаимодействия? Если да, что еще происходило в основном потоке в это время?»
- «Вызвало ли это взаимодействие большую работу по рендерингу, которая задержала прорисовку следующего кадра?»
В следующей таблице показаны некоторые основные данные атрибуции, которые вы можете получить из библиотеки и которые помогут вам выяснить некоторые общие причины медленного взаимодействия на вашем веб-сайте:
ключ объекта attribution | Данные |
---|---|
interactionTarget | Селектор CSS, указывающий на элемент, создавший значение INP страницы, например button#save . |
interactionType | Тип взаимодействия: щелчки, касания или ввод с клавиатуры. |
inputDelay * | Задержка ввода взаимодействия. |
processingDuration * | Время с момента запуска первого прослушивателя событий в ответ на взаимодействие с пользователем до завершения всей обработки прослушивателя событий. |
presentationDelay * | Задержка представления взаимодействия, которая происходит с момента завершения обработчиков событий до момента рисования следующего кадра. |
longAnimationFrameEntries * | Записи из LoAF, связанные с взаимодействием. Дополнительную информацию смотрите далее. |
Начиная с версии 4 библиотеки web-vitals, вы можете получить еще более глубокое понимание проблемных взаимодействий с помощью данных, которые она предоставляет с разбивкой по фазам INP (задержка ввода, продолжительность обработки и задержка представления) и API длинных анимационных кадров (LoAF) .
API длинных кадров анимации (LoAF)
Отладка взаимодействий с использованием полевых данных — сложная задача. Однако с помощью данных LoAF теперь можно лучше понять причины медленного взаимодействия, поскольку LoAF предоставляет ряд подробных таймингов и других данных, которые вы можете использовать для точного определения точных причин — и, что более важно, того, где находится источник проблемы в коде вашего веб-сайта.
Сборка атрибуции библиотеки web-vitals предоставляет массив записей LoAF под ключом longAnimationFrameEntries
объекта attribution
. В следующей таблице перечислены несколько ключевых битов данных, которые вы можете найти в каждой записи LoAF:
Ключ объекта входа LoAF | Данные |
---|---|
duration | Продолжительность длинного кадра анимации до завершения макета, но исключая рисование и композицию. |
blockingDuration | Общее количество времени в кадре, в течение которого браузер не мог быстро отреагировать из-за длительных задач. Это время блокировки может включать в себя длительные задачи, выполняющие JavaScript, а также любые последующие длительные задачи рендеринга в кадре. |
firstUIEventTimestamp | Временная метка того, когда событие было поставлено в очередь во время кадра. Полезно для определения начала задержки ввода взаимодействия. |
startTime | Начальная временная метка кадра. |
renderStart | Когда началась работа по рендерингу кадра. Сюда входят любые обратные вызовы requestAnimationFrame (и обратные вызовы ResizeObserver , если применимо), но, возможно, до начала какой-либо работы со стилем/макетом. |
styleAndLayoutStart | Когда происходит работа над стилем/макетом в кадре. Может быть полезно при определении продолжительности работы над стилем/макетом при определении других доступных временных меток. |
scripts | Массив элементов, содержащих информацию об атрибуции сценария, вносящую вклад в INP страницы. |

blockingDuration
). Вся эта информация может многое рассказать вам о том, что замедляет взаимодействие, но особый интерес должен представлять массив scripts
, отображаемый в записях LoAF:
Ключ объекта атрибуции скрипта | Данные |
---|---|
invoker | Вызывающий. Это может варьироваться в зависимости от типа инициатора, описанного в следующей строке. Примерами инициаторов могут быть такие значения, как 'IMG#id.onload' , 'Window.requestAnimationFrame' или 'Response.json.then' . |
invokerType | Тип вызывающего. Может быть 'user-callback' , 'event-listener' , 'resolve-promise' , 'reject-promise' , 'classic-script' или 'module-script' . |
sourceURL | URL-адрес сценария, из которого был создан длинный кадр анимации. |
sourceCharPosition | Позиция символа в скрипте, определяемая sourceURL . |
sourceFunctionName | Имя функции в идентифицированном скрипте. |
Каждая запись в этом массиве содержит данные, показанные в этой таблице, которые дают вам информацию о сценарии, который был ответственен за медленное взаимодействие, и о том, как он виноват.
Измерьте и определите общие причины медленного взаимодействия
Чтобы дать вам представление о том, как вы можете использовать эту информацию, в этом руководстве мы рассмотрим, как вы можете использовать данные LoAF, представленные в библиотеке web-vitals
для определения некоторых причин медленного взаимодействия.
Длительная продолжительность обработки
Продолжительность обработки взаимодействия — это время, необходимое для завершения зарегистрированных обратных вызовов обработчика событий взаимодействия и всего остального, что может произойти между ними. О высокой продолжительности обработки свидетельствует библиотека веб-виталов:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {processingDuration} = attribution; // 512.5
});
Естественно думать, что основной причиной медленного взаимодействия является то, что код обработчика событий выполнялся слишком долго, но это не всегда так! Как только вы подтвердите, что это проблема, вы можете копнуть глубже с данными LoAF:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {processingDuration} = attribution; // 512.5
// Get the longest script from LoAF covering `processingDuration`:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
if (script) {
// Get attribution for the long-running event handler:
const {invokerType} = script; // 'event-listener'
const {invoker} = script; // 'BUTTON#update.onclick'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Как видно из предыдущего фрагмента кода, вы можете работать с данными LoAF, чтобы отслеживать точную причину взаимодействия со значениями высокой продолжительности обработки, включая:
- Элемент и его зарегистрированный прослушиватель событий.
- Файл сценария (и позиция символа в нем), содержащий код обработчика долговременных событий.
- Имя функции.
Этот тип данных бесценен. Вам больше не нужно утомлять себя поиском того, какое именно взаимодействие (или какой из его обработчиков событий) отвечает за высокие значения длительности обработки. Кроме того, поскольку сторонние сценарии часто могут регистрировать свои собственные обработчики событий, вы можете определить, виноват ли в этом ваш код! Для кода, который вы контролируете, вам следует изучить возможность оптимизации длинных задач .
Длительные задержки ввода
Хотя обработчики событий с длительным выполнением являются обычным явлением, существуют и другие части взаимодействия, которые следует учитывать. Одна часть происходит до начала обработки, которая известна как задержка ввода . Это время с момента, когда пользователь инициирует взаимодействие, до момента, когда начинают выполняться обратные вызовы его обработчика событий, и это происходит, когда основной поток уже обрабатывает другую задачу. Сборка атрибуции библиотеки web-vitals может сообщить вам продолжительность задержки ввода для взаимодействия:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
});
Если вы заметили, что некоторые взаимодействия имеют большие задержки ввода, вам нужно будет выяснить, что происходило на странице в момент взаимодействия, вызвавшего длительную задержку ввода — и это часто сводится к тому, произошло ли взаимодействие во время загрузки страницы или после нее.
Это было во время загрузки страницы?
Основной поток часто бывает наиболее загружен во время загрузки страницы. В это время всевозможные задачи ставятся в очередь и обрабатываются, и если пользователь попытается взаимодействовать со страницей во время всей этой работы, это может задержать взаимодействие. Страницы, загружающие много JavaScript, могут запускать работу по компиляции и оценке сценариев, а также выполнять функции, которые подготавливают страницу к взаимодействию с пользователем. Эта работа может помешать, если пользователь взаимодействует во время этого действия, и вы можете выяснить, так ли это для пользователей вашего веб-сайта:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
// Get the longest script from the first LoAF entry:
const loaf = attribution.longAnimationFrameEntries[0];
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
if (script) {
// Invoker types can describe if script eval blocked the main thread:
const {invokerType} = script; // 'classic-script' | 'module-script'
const {sourceLocation} = script; // 'https://example.com/app.js'
}
});
Если вы записываете эти данные в поле и видите большие задержки ввода и типы активаторов 'classic-script'
или 'module-script'
, то справедливо будет сказать, что сценарии на вашем сайте требуют много времени для оценки и блокируют основной поток достаточно долго, чтобы задержать взаимодействие. Вы можете сократить время блокировки, разбив скрипты на более мелкие пакеты, отложив загрузку изначально неиспользуемого кода на более поздний момент и проверив свой сайт на наличие неиспользуемого кода, который можно полностью удалить.
Это было после загрузки страницы?
Хотя задержки ввода часто возникают во время загрузки страницы, вполне возможно, что они могут возникнуть и после загрузки страницы по совершенно другой причине. Распространенными причинами задержек ввода после загрузки страницы может быть код, который периодически выполняется из-за более раннего вызова setInterval
, или даже обратные вызовы событий, которые были поставлены в очередь для запуска ранее и все еще обрабатываются.
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
// Get the longest script from the first LoAF entry:
const loaf = attribution.longAnimationFrameEntries[0];
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
if (script) {
const {invokerType} = script; // 'user-callback'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Как и в случае с устранением неполадок с высокими значениями продолжительности обработки, высокие задержки ввода по причинам, упомянутым ранее, предоставят вам подробные данные об атрибуции сценария. Однако отличие заключается в том, что тип инициатора будет меняться в зависимости от характера работы, которая задержала взаимодействие:
-
'user-callback'
указывает, что задача блокировки была изsetInterval
,setTimeout
или дажеrequestAnimationFrame
. -
'event-listener'
указывает, что задача блокировки была взята из более раннего ввода, который был поставлен в очередь и все еще обрабатывается. -
'resolve-promise'
и'reject-promise'
означают, что задача блокировки возникла в результате какой-то асинхронной работы, которая была запущена ранее и решена или отклонена в тот момент, когда пользователь пытался взаимодействовать со страницей, что задерживает взаимодействие.
В любом случае данные об атрибуции скрипта дадут вам представление о том, с чего начать поиск и была ли задержка ввода вызвана вашим собственным кодом или кодом стороннего скрипта.
Длительные задержки презентации
Задержки представления — это последняя миля взаимодействия, они начинаются, когда завершаются обработчики событий взаимодействия, вплоть до момента рисования следующего кадра. Они возникают, когда работа в обработчике событий вследствие взаимодействия меняет визуальное состояние пользовательского интерфейса. Как и в случае с длительностью обработки и задержками ввода, библиотека веб-виталов может сообщить вам, как долго длилась задержка презентации для взаимодействия:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 113.32307691
});
Если вы записываете эти данные и видите высокие задержки представления взаимодействий, способствующих INP вашего веб-сайта, виновники могут быть разными, но вот несколько причин, на которые следует обратить внимание.
Дорогая стилистика и верстка.
Длительные задержки представления могут быть дорогостоящими пересчетами стилей и работой по макету , что возникает по ряду причин, включая сложные селекторы CSS и большие размеры DOM . Вы можете измерить продолжительность этой работы с временем буханки, появившимися в библиотеке веб-виталов:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 113.32307691
// Get the longest script from the last LoAF entry:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
// Get necessary timings:
const {startTime} = loaf; // 2120.5
const {duration} = loaf; // 1002
// Figure out the ending timestamp of the frame (approximate):
const endTime = startTime + duration; // 3122.5
// Get the start timestamp of the frame's style/layout work:
const {styleAndLayoutStart} = loaf; // 3011.17692309
// Calculate the total style/layout duration:
const styleLayoutDuration = endTime - styleAndLayoutStart; // 111.32307691
if (script) {
// Get attribution for the event handler that triggered
// the long-running style and layout operation:
const {invokerType} = script; // 'event-listener'
const {invoker} = script; // 'BUTTON#update.onclick'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Loaf не скажет вам продолжительность работы стиля и макета для кадры, но он скажет вам, когда он начнется. С помощью этой начальной временной метки вы можете использовать другие данные из Loaf для расчета точной продолжительности этой работы, определяя время окончания кадра и вычитая начальную метку времен стиля и макета.
Давние обратные вызовы requestAnimationFrame
Одной из потенциальных причин задержек длинных презентаций является чрезмерная работа, выполненная в обратном вызове requestAnimationFrame
. Содержание этого обратного вызова выполняется после того, как обработчики событий закончили работу, но незадолго до перечисления в стиле и работы макета.
Эти обратные вызовы могут занять значительное время, чтобы завершить, если работа, выполненная внутри них, сложна. Если вы подозреваете, что высокие значения задержки презентации связаны с работой, которую вы выполняете с requestAnimationFrame
, вы можете использовать данные буханки, появившиеся в библиотеке веб-виталов для определения этих сценариев:
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 543.1999999880791
// Get the longest script from the last LoAF entry:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
// Get the render start time and when style and layout began:
const {renderStart} = loaf; // 2489
const {styleAndLayoutStart} = loaf; // 2989.5999999940395
// Calculate the `requestAnimationFrame` callback's duration:
const rafDuration = styleAndLayoutStart - renderStart; // 500.59999999403954
if (script) {
// Get attribution for the event handler that triggered
// the long-running requestAnimationFrame callback:
const {invokerType} = script; // 'user-callback'
const {invoker} = script; // 'FrameRequestCallback'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Если вы видите, что значительная часть времени задержки презентации проводится в обратном вызове requestAnimationFrame
, убедитесь, что работа, которую вы выполняете в этих вызовах, ограничена выполнением работы, которая приводит к фактическому обновлению пользовательского интерфейса. Любая другая работа, которая не касается стилей DOM или обновления, излишне задержит следующий кадр от окрашивания, так что будьте осторожны!
Заключение
Полевые данные - лучший источник информации, на котором вы можете опираться, когда речь заходит о понимании, какие взаимодействия являются проблематичными для реальных пользователей в этой области. Полагаясь на инструменты сбора полевых данных, такие как библиотека JavaScript Web-Vitals (или поставщик ромов), вы можете быть более уверенным в том, какие взаимодействия наиболее проблематичны, а затем перейти к воспроизведению проблемных взаимодействий в лаборатории , а затем продолжить их исправление.
Герой Изображение от Unsplash , Federico Respini .
,Узнайте, как найти медленное взаимодействие в полевых данных вашего сайта, чтобы вы могли найти возможности для улучшения его взаимодействия с следующей краской.
Полевые данные - это данные, которые рассказывают вам, как фактические пользователи испытывают ваш сайт. Это дразнит проблемы, которые вы не можете найти в лабораторных данных . Что касается взаимодействия с следующей краской (INP) , полевые данные необходимы для определения медленных взаимодействий и дают жизненно важные подсказки, чтобы помочь вам исправить их.
В этом руководстве вы узнаете, как быстро оценить INP вашего веб -сайта, используя полевые данные из отчета о опыте работы с пользователем Chrome (CRUX), чтобы увидеть, есть ли у вашего веб -сайта проблемы с INP. Впоследствии вы узнаете, как использовать построение атрибуции библиотеки JavaScript Web-Vitals -и новое понимание, которое она предоставляет из API длинных анимационных кадров (Loaf) -чтобы собрать и интерпретировать полевые данные для медленных взаимодействий на вашем сайте.
Начните с CRUX, чтобы оценить INP вашего сайта
Если вы не собираете полевые данные у пользователей вашего сайта, CRUX может быть хорошей отправной точкой. CRUX собирает полевые данные от реальных пользователей Chrome, которые решили отправлять данные телеметрии.
Данные о Cux появляются в ряде различных областей, и это зависит от объема информации, которую вы ищете. Crux может предоставить данные в INP и других основных веб -жизненных возможностях для:
- Отдельные страницы и все происхождение с использованием PageSpeed Insights .
- Типы страниц. Например, многие веб -сайты электронной коммерции имеют страницу сведений о продукте и типы страниц списка продуктов. Вы можете получить данные CRUX для уникальных типов страниц в консоли поиска .
В качестве отправной точки вы можете ввести URL вашего сайта в PageSpeed Insights. После того, как вы введете URL, полевые данные для него - если будут доступны - будут отображаться для нескольких метрик, включая INP. Вы также можете использовать переключатели, чтобы проверить значения INP для мобильных и настольных размеров.

Эти данные полезны, потому что он говорит вам, есть ли у вас проблема. Однако, что Crux не может сделать, так это сказать вам, что вызывает проблемы. Существует множество реальных решений для мониторинга пользователей (RUM), которые помогут вам собрать свои собственные полевые данные от пользователей вашего веб-сайта, чтобы помочь вам ответить на это, и один из вариантов состоит в том, чтобы самостоятельно собрать эти полевые данные, используя библиотеку JavaScript Web-Vitals.
Соберите полевые данные с библиотекой JavaScript web-vitals
Библиотека JavaScript web-vitals
-это сценарий, который вы можете загрузить на свой веб-сайт, чтобы собрать данные поля у пользователей вашего веб-сайта. Вы можете использовать его для записи ряда метрик, включая INP в браузерах, которые поддерживают его.
Стандартная сборка библиотеки Web-Vitals может использоваться для получения основных данных INP от пользователей в этой области:
import {onINP} from 'web-vitals';
onINP(({name, value, rating}) => {
console.log(name); // 'INP'
console.log(value); // 512
console.log(rating); // 'poor'
});
Чтобы проанализировать ваши полевые данные от ваших пользователей, вы захотите куда -нибудь отправить эти данные:
import {onINP} from 'web-vitals';
onINP(({name, value, rating}) => {
// Prepare JSON to be sent for collection. Note that
// you can add anything else you'd want to collect here:
const body = JSON.stringify({name, value, rating});
// Use `sendBeacon` to send data to an analytics endpoint.
// For Google Analytics, see https://github.com/GoogleChrome/web-vitals#send-the-results-to-google-analytics.
navigator.sendBeacon('/analytics', body);
});
Тем не менее, эти данные само по себе не говорят вам гораздо больше, чем Крукс. Вот где появляется сборка библиотеки веб-виталов.
Идите дальше с сборкой атрибуции библиотеки веб-виталов
Построение атрибуции библиотеки веб-виталов поверхностных данных, которые вы можете получить от пользователей в этой области, чтобы помочь вам лучше устранения проблемных взаимодействий, которые влияют на INP вашего веб-сайта. Эти данные доступны через объект attribution
всплывший в методе библиотеки onINP()
:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, rating, attribution}) => {
console.log(name); // 'INP'
console.log(value); // 56
console.log(rating); // 'good'
console.log(attribution); // Attribution data object
});

В дополнение к самой странице INP, сборка атрибуции предоставляет много данных, которые вы можете использовать, чтобы помочь понять причины медленного взаимодействия, в том числе на какую часть взаимодействия вы должны сосредоточиться. Это может помочь вам ответить на важные вопросы, такие как:
- «Пользователь взаимодействовал со страницей во время загрузки?»
- "Работали ли обработчики событий взаимодействия долгое время?"
- «Был ли задержен код обработчика событий взаимодействия от запуска? Если да, то что еще происходит в основном потоке в то время?»
- «Привело ли это взаимодействие много работ, которые задержали следующую кадр от окрашивания?»
В следующей таблице показаны некоторые основные данные атрибуции, которые вы можете получить из библиотеки, которые могут помочь вам выяснить некоторые высокие причины медленных взаимодействий на вашем сайте:
Ключ объекта attribution | Данные |
---|---|
interactionTarget | Селектор CSS, указывающий на элемент, который создал значение INP страницы, например, button#save . |
interactionType | Тип взаимодействия, либо от кликов, кранов или входов клавиатуры. |
inputDelay * | Задержка ввода взаимодействия. |
processingDuration | Время, когда первый слушатель событий начал работать в ответ на взаимодействие с пользователем до тех пор, пока не завершена вся обработка слушателя событий. |
presentationDelay * | Задержка презентации взаимодействия, которая происходит, начиная с того, когда обработчики событий заканчиваются до того времени, когда нарисована следующая кадр. |
longAnimationFrameEntries * | Записи из буханки, связанные с взаимодействием. Смотрите следующую для получения дополнительной информации. |
Начиная с версии 4 библиотеки Web-Vitals, вы можете получить еще более глубокое понимание проблемных взаимодействий с помощью данных, которые он предоставляет с разбивками фазы INP (задержка ввода, продолжительность обработки и задержка презентации) и API с длинными анимационными кадрами (Loaf) .
Длинные анимационные кадры API (Loaf)
Отладка взаимодействия с использованием полевых данных является сложной задачей. Однако с помощью данных из Loaf теперь можно лучше понять причины медленных взаимодействий, поскольку Loaf раскрывает ряд подробных сроков и других данных, которые вы можете использовать для определения точных причин - и, что более важно, когда источник проблемы находится в коде вашего веб -сайта.
Сборка атрибуции библиотеки веб-виталов разоблачает массив записей Loaf в рамках ключа longAnimationFrameEntries
объекта attribution
. В следующей таблице перечислены несколько ключевых бит данных, которые вы можете найти в каждой записи Loaf:
Ключ объекта входа в буханку | Данные |
---|---|
duration | Продолжительность длинной анимационной рамки, вплоть до того, когда макет завершился, но исключая живопись и композицию. |
blockingDuration | Общее количество времени в кадре, на которое браузер не смог быстро реагировать из -за длинных задач. Это время блокировки может включать в себя длинные задачи, выполняющие JavaScript, а также любую последующую задачу длинного рендеринга в кадре. |
firstUIEventTimestamp | TimeStamp of Time, когда событие было в очереди во время кадра. Полезно для выяснения начала задержки ввода взаимодействия. |
startTime | Начальная метка времени кадра. |
renderStart | Когда началась рендеринг для кадры. Это включает в себя любые обратные вызовы requestAnimationFrame (и обратные вызовы ResizeObserver , если применимо), но, возможно, до начала каких -либо стилей/макета. |
styleAndLayoutStart | Когда происходит стиль/макет в рамке. Может быть полезен при выяснении длины работы стиля/макета при выяснении в других доступных временных метках. |
scripts | Множество элементов, содержащих информацию о атрибуции скрипта, вносящая вклад в INP страницы. |

blockingDuration
). Вся эта информация может многое рассказать вам о том, что делает взаимодействие медленным, но массив scripts
, который поверхность блоков буханки должен представлять особый интерес:
Ключ объекта атрибуции скрипта | Данные |
---|---|
invoker | Invoker. Это может варьироваться в зависимости от типа Invoker, описанного в следующем ряду. Примерами Invokers могут быть такие значения, как 'IMG#id.onload' , 'Window.requestAnimationFrame' или 'Response.json.then' . |
invokerType | Тип инвента. Может быть 'user-callback' , 'event-listener' , 'resolve-promise' , 'reject-promise' , 'classic-script' или 'module-script' . |
sourceURL | URL -адрес сценария, откуда происходил длинная анимационная кадра. |
sourceCharPosition | Позиция символа в сценарии, идентифицированную sourceURL . |
sourceFunctionName | Имя функции в идентифицированном сценарии. |
Каждая запись в этом массиве содержит данные, показанные в этой таблице, которые дают вам информацию о сценарии, который отвечал за медленное взаимодействие, и о том, как оно отвечало.
Измерить и определить общие причины медленных взаимодействий
Чтобы дать вам представление о том, как вы можете использовать эту информацию, это руководство теперь пройдет через то, как вы можете использовать данные буханки, появившиеся в библиотеке web-vitals
чтобы определить некоторые причины медленных взаимодействий.
Длительная продолжительность обработки
Продолжительность обработки взаимодействия - это время, которое необходимо для зарегистрированных обратных вызовов, обработанных зарегистрированным событием, для завершения и всего, что может произойти между ними. Высокая продолжительность обработки оказывается библиотекой веб-виталов:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {processingDuration} = attribution; // 512.5
});
Естественно думать, что основная причина медленного взаимодействия состоит в том, что ваш код обработчика мероприятий занимал слишком много времени, чтобы запустить, но это не всегда так! После того, как вы подтвердили, что это проблема, вы можете копать глубже с данными буханки:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {processingDuration} = attribution; // 512.5
// Get the longest script from LoAF covering `processingDuration`:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
if (script) {
// Get attribution for the long-running event handler:
const {invokerType} = script; // 'event-listener'
const {invoker} = script; // 'BUTTON#update.onclick'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Как вы можете видеть в предыдущем фрагменте кода, вы можете работать с данными Loaf, чтобы отследить точную причину взаимодействия с высокими значениями продолжительности обработки, включая:
- Элемент и его зарегистрированный слушатель событий.
- Файл сценария-и позиция символа в нем-содержит длительный код обработчика событий.
- Имя функции.
Этот тип данных бесценен. Вам больше не нужно выполнять работу, чтобы точно выяснить, какое взаимодействие - или какое из его обработчиков событий - отвечало за высокие значения продолжительности обработки. Кроме того, поскольку сторонние сценарии часто могут зарегистрировать свои собственные обработчики событий, вы можете определить, был ли ваш код, который был ответственным! Для кода, который у вас есть контроль, вы захотите изучить оптимизацию длинных задач .
Длинные входные задержки
В то время как длительные обработчики событий являются обычными, есть и другие части взаимодействия, которые следует учитывать. Одна часть происходит до продолжительности обработки, которая известна как задержка ввода . Это время, когда пользователь инициирует взаимодействие, до момента, как его обратные вызовы событий начинают работать и происходит, когда основной поток уже обрабатывает другую задачу. Сборка атрибуции библиотеки веб-виталов может сообщить вам о длине задержки ввода для взаимодействия:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
});
Если вы заметите, что некоторые взаимодействия имеют высокие задержки ввода, вам нужно выяснить, что происходит на странице во время взаимодействия, которое вызвало длительную задержку ввода, и это часто сводится к тому, произошло ли взаимодействие, когда страница загружалась, или после этого.
Было ли это во время загрузки страницы?
Основная поток часто бывает наиболее загруженной, поскольку страница загружается. В течение этого времени все виды задач подвергаются в очередь и обрабатываются, и если пользователь пытается взаимодействовать со страницей, в то время как вся эта работа происходит, это может задержать взаимодействие. Страницы, которые загружают много JavaScript, могут начать работу для компиляции и оценки сценариев, а также выполнения функций, которые поднимают страницу для взаимодействия с пользователем. Эта работа может мешать, если пользователь взаимодействует с этим действием, и вы можете выяснить, имеет ли это место для пользователей вашего веб -сайта:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
// Get the longest script from the first LoAF entry:
const loaf = attribution.longAnimationFrameEntries[0];
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
if (script) {
// Invoker types can describe if script eval blocked the main thread:
const {invokerType} = script; // 'classic-script' | 'module-script'
const {sourceLocation} = script; // 'https://example.com/app.js'
}
});
Если вы записываете эти данные в этой области и видите высокие задержки ввода и типы Invoker 'classic-script'
или 'module-script'
, то справедливо сказать, что сценарии на вашем сайте занимают много времени для оценки и блокируют основной теме достаточно долго, чтобы задержать взаимодействия. Вы можете сократить это время блокировки, разбив свои сценарии на более мелкие пакеты, отложите изначально неиспользованный код, который будет загружен в более поздний момент времени, и проверить ваш сайт для неиспользованного кода, который вы можете полностью удалить.
Это было после загрузки страницы?
В то время как задержки ввода часто возникают во время загрузки страницы, максимально возможно, что они могут возникнуть после загрузки страницы, из -за совершенно другой причины. Общие причины входных задержек после загрузки страницы могут быть код, который периодически работает из -за более раннего вызова setInterval
, или даже обратных вызовов событий, которые были в очереди, чтобы запустить ранее, и все еще обрабатываются.
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
// Get the longest script from the first LoAF entry:
const loaf = attribution.longAnimationFrameEntries[0];
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
if (script) {
const {invokerType} = script; // 'user-callback'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Как и в случае с устранением неполадок высоких значений продолжительности обработки, высокие входные задержки по причинам, упомянутым ранее, дадут вам подробные данные атрибуции скрипта. Однако отличается то, что тип Invoker будет изменяться в зависимости от характера работы, которая задержала взаимодействие:
-
'user-callback'
указывает, что задача блокировки была отsetInterval
,setTimeout
или дажеrequestAnimationFrame
. -
'event-listener'
указывает на то, что задача блокировки была от более раннего ввода, который был в очередь и все еще обрабатывался. -
'resolve-promise'
и'reject-promise'
означает, что задача блокировки была из какой-то асинхронной работы, которая была запущена ранее, и разрешается или отвергнута в то время, когда пользователь попытался взаимодействовать со страницей, откладывая взаимодействие.
В любом случае, данные атрибуции скрипта дадут вам представление о том, с чего начать искать, и была ли задержка ввода из-за вашего собственного кода или сценария стороннего сценария.
Длинные задержки в презентации
Задержки с презентацией являются последней милей взаимодействия, и начинаются, когда обработчики событий взаимодействия заканчиваются, вплоть до того, что следующий кадр был окрашен. Они происходят, когда работа в обработке событий из -за взаимодействия меняет визуальное состояние пользовательского интерфейса. Как и в случае с продолжительностью обработки и входных задержек, библиотека Web-Vitals может сказать вам, как долго задержка презентации была для взаимодействия:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 113.32307691
});
Если вы записываете эти данные и увидите высокие задержки для презентации для взаимодействия, способствующих INP вашего сайта, виновники могут различаться, но вот пара причин для поиска.
Дорогой стиль и макет
Длинные задержки презентации могут быть дорогостоящим перечислением в стиле и работе с макетами , которые возникают по ряду причин, включая сложные селекторы CSS и большие размеры DOM . Вы можете измерить продолжительность этой работы с временем буханки, появившимися в библиотеке веб-виталов:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 113.32307691
// Get the longest script from the last LoAF entry:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
// Get necessary timings:
const {startTime} = loaf; // 2120.5
const {duration} = loaf; // 1002
// Figure out the ending timestamp of the frame (approximate):
const endTime = startTime + duration; // 3122.5
// Get the start timestamp of the frame's style/layout work:
const {styleAndLayoutStart} = loaf; // 3011.17692309
// Calculate the total style/layout duration:
const styleLayoutDuration = endTime - styleAndLayoutStart; // 111.32307691
if (script) {
// Get attribution for the event handler that triggered
// the long-running style and layout operation:
const {invokerType} = script; // 'event-listener'
const {invoker} = script; // 'BUTTON#update.onclick'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Loaf не скажет вам продолжительность работы стиля и макета для кадры, но он скажет вам, когда он начнется. С помощью этой начальной временной метки вы можете использовать другие данные из Loaf для расчета точной продолжительности этой работы, определяя время окончания кадра и вычитая начальную метку времен стиля и макета.
Давние обратные вызовы requestAnimationFrame
Одной из потенциальных причин задержек длинных презентаций является чрезмерная работа, выполненная в обратном вызове requestAnimationFrame
. Содержание этого обратного вызова выполняется после того, как обработчики событий закончили работу, но незадолго до перечисления в стиле и работы макета.
Эти обратные вызовы могут занять значительное время, чтобы завершить, если работа, выполненная внутри них, сложна. Если вы подозреваете, что высокие значения задержки презентации связаны с работой, которую вы выполняете с requestAnimationFrame
, вы можете использовать данные буханки, появившиеся в библиотеке веб-виталов для определения этих сценариев:
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 543.1999999880791
// Get the longest script from the last LoAF entry:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
// Get the render start time and when style and layout began:
const {renderStart} = loaf; // 2489
const {styleAndLayoutStart} = loaf; // 2989.5999999940395
// Calculate the `requestAnimationFrame` callback's duration:
const rafDuration = styleAndLayoutStart - renderStart; // 500.59999999403954
if (script) {
// Get attribution for the event handler that triggered
// the long-running requestAnimationFrame callback:
const {invokerType} = script; // 'user-callback'
const {invoker} = script; // 'FrameRequestCallback'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Если вы видите, что значительная часть времени задержки презентации проводится в обратном вызове requestAnimationFrame
, убедитесь, что работа, которую вы выполняете в этих вызовах, ограничена выполнением работы, которая приводит к фактическому обновлению пользовательского интерфейса. Любая другая работа, которая не касается стилей DOM или обновления, излишне задержит следующий кадр от окрашивания, так что будьте осторожны!
Заключение
Полевые данные - лучший источник информации, на котором вы можете опираться, когда речь заходит о понимании, какие взаимодействия являются проблематичными для реальных пользователей в этой области. Полагаясь на инструменты сбора полевых данных, такие как библиотека JavaScript Web-Vitals (или поставщик ромов), вы можете быть более уверенным в том, какие взаимодействия наиболее проблематичны, а затем перейти к воспроизведению проблемных взаимодействий в лаборатории , а затем продолжить их исправление.
Герой Изображение от Unsplash , Federico Respini .
,Узнайте, как найти медленное взаимодействие в полевых данных вашего сайта, чтобы вы могли найти возможности для улучшения его взаимодействия с следующей краской.
Полевые данные - это данные, которые рассказывают вам, как фактические пользователи испытывают ваш сайт. Это дразнит проблемы, которые вы не можете найти в лабораторных данных . Что касается взаимодействия с следующей краской (INP) , полевые данные необходимы для определения медленных взаимодействий и дают жизненно важные подсказки, чтобы помочь вам исправить их.
В этом руководстве вы узнаете, как быстро оценить INP вашего веб -сайта, используя полевые данные из отчета о опыте работы с пользователем Chrome (CRUX), чтобы увидеть, есть ли у вашего веб -сайта проблемы с INP. Впоследствии вы узнаете, как использовать построение атрибуции библиотеки JavaScript Web-Vitals -и новое понимание, которое она предоставляет из API длинных анимационных кадров (Loaf) -чтобы собрать и интерпретировать полевые данные для медленных взаимодействий на вашем сайте.
Начните с CRUX, чтобы оценить INP вашего сайта
Если вы не собираете полевые данные у пользователей вашего сайта, CRUX может быть хорошей отправной точкой. CRUX собирает полевые данные от реальных пользователей Chrome, которые решили отправлять данные телеметрии.
Данные о Cux появляются в ряде различных областей, и это зависит от объема информации, которую вы ищете. Crux может предоставить данные в INP и других основных веб -жизненных возможностях для:
- Отдельные страницы и все происхождение с использованием PageSpeed Insights .
- Типы страниц. Например, многие веб -сайты электронной коммерции имеют страницу сведений о продукте и типы страниц списка продуктов. Вы можете получить данные CRUX для уникальных типов страниц в консоли поиска .
В качестве отправной точки вы можете ввести URL вашего сайта в PageSpeed Insights. После того, как вы введете URL, полевые данные для него - если будут доступны - будут отображаться для нескольких метрик, включая INP. Вы также можете использовать переключатели, чтобы проверить значения INP для мобильных и настольных размеров.

Эти данные полезны, потому что он говорит вам, есть ли у вас проблема. Однако, что Crux не может сделать, так это сказать вам, что вызывает проблемы. Существует множество реальных решений для мониторинга пользователей (RUM), которые помогут вам собрать свои собственные полевые данные от пользователей вашего веб-сайта, чтобы помочь вам ответить на это, и один из вариантов состоит в том, чтобы самостоятельно собрать эти полевые данные, используя библиотеку JavaScript Web-Vitals.
Соберите полевые данные с библиотекой JavaScript web-vitals
Библиотека JavaScript web-vitals
-это сценарий, который вы можете загрузить на свой веб-сайт, чтобы собрать данные поля у пользователей вашего веб-сайта. Вы можете использовать его для записи ряда метрик, включая INP в браузерах, которые поддерживают его.
Стандартная сборка библиотеки Web-Vitals может использоваться для получения основных данных INP от пользователей в этой области:
import {onINP} from 'web-vitals';
onINP(({name, value, rating}) => {
console.log(name); // 'INP'
console.log(value); // 512
console.log(rating); // 'poor'
});
Чтобы проанализировать ваши полевые данные от ваших пользователей, вы захотите куда -нибудь отправить эти данные:
import {onINP} from 'web-vitals';
onINP(({name, value, rating}) => {
// Prepare JSON to be sent for collection. Note that
// you can add anything else you'd want to collect here:
const body = JSON.stringify({name, value, rating});
// Use `sendBeacon` to send data to an analytics endpoint.
// For Google Analytics, see https://github.com/GoogleChrome/web-vitals#send-the-results-to-google-analytics.
navigator.sendBeacon('/analytics', body);
});
Тем не менее, эти данные само по себе не говорят вам гораздо больше, чем Крукс. Вот где появляется сборка библиотеки веб-виталов.
Идите дальше с сборкой атрибуции библиотеки веб-виталов
Построение атрибуции библиотеки веб-виталов поверхностных данных, которые вы можете получить от пользователей в этой области, чтобы помочь вам лучше устранения проблемных взаимодействий, которые влияют на INP вашего веб-сайта. Эти данные доступны через объект attribution
всплывший в методе библиотеки onINP()
:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, rating, attribution}) => {
console.log(name); // 'INP'
console.log(value); // 56
console.log(rating); // 'good'
console.log(attribution); // Attribution data object
});

В дополнение к самой странице INP, сборка атрибуции предоставляет много данных, которые вы можете использовать, чтобы помочь понять причины медленного взаимодействия, в том числе на какую часть взаимодействия вы должны сосредоточиться. Это может помочь вам ответить на важные вопросы, такие как:
- «Пользователь взаимодействовал со страницей во время загрузки?»
- "Работали ли обработчики событий взаимодействия долгое время?"
- «Был ли задержен код обработчика событий взаимодействия от запуска? Если да, то что еще происходит в основном потоке в то время?»
- «Привело ли это взаимодействие много работ, которые задержали следующую кадр от окрашивания?»
В следующей таблице показаны некоторые основные данные атрибуции, которые вы можете получить из библиотеки, которые могут помочь вам выяснить некоторые высокие причины медленных взаимодействий на вашем сайте:
Ключ объекта attribution | Данные |
---|---|
interactionTarget | Селектор CSS, указывающий на элемент, который создал значение INP страницы, например, button#save . |
interactionType | Тип взаимодействия, либо от кликов, кранов или входов клавиатуры. |
inputDelay * | Задержка ввода взаимодействия. |
processingDuration | Время, когда первый слушатель событий начал работать в ответ на взаимодействие с пользователем до тех пор, пока не завершена вся обработка слушателя событий. |
presentationDelay * | Задержка презентации взаимодействия, которая происходит, начиная с того, когда обработчики событий заканчиваются до того времени, когда нарисована следующая кадр. |
longAnimationFrameEntries * | Записи из буханки, связанные с взаимодействием. Смотрите следующую для получения дополнительной информации. |
Начиная с версии 4 библиотеки Web-Vitals, вы можете получить еще более глубокое понимание проблемных взаимодействий с помощью данных, которые он предоставляет с разбивками фазы INP (задержка ввода, продолжительность обработки и задержка презентации) и API с длинными анимационными кадрами (Loaf) .
Длинные анимационные кадры API (Loaf)
Отладка взаимодействия с использованием полевых данных является сложной задачей. Однако с помощью данных из Loaf теперь можно лучше понять причины медленных взаимодействий, поскольку Loaf раскрывает ряд подробных сроков и других данных, которые вы можете использовать для определения точных причин - и, что более важно, когда источник проблемы находится в коде вашего веб -сайта.
Сборка атрибуции библиотеки веб-виталов разоблачает массив записей Loaf в рамках ключа longAnimationFrameEntries
объекта attribution
. В следующей таблице перечислены несколько ключевых бит данных, которые вы можете найти в каждой записи Loaf:
Ключ объекта входа в буханку | Данные |
---|---|
duration | Продолжительность длинной анимационной рамки, вплоть до того, когда макет завершился, но исключая живопись и композицию. |
blockingDuration | Общее количество времени в кадре, на которое браузер не смог быстро реагировать из -за длинных задач. Это время блокировки может включать в себя длинные задачи, выполняющие JavaScript, а также любую последующую задачу длинного рендеринга в кадре. |
firstUIEventTimestamp | TimeStamp of Time, когда событие было в очереди во время кадра. Полезно для выяснения начала задержки ввода взаимодействия. |
startTime | Начальная метка времени кадра. |
renderStart | Когда началась рендеринг для кадры. Это включает в себя любые обратные вызовы requestAnimationFrame (и обратные вызовы ResizeObserver , если применимо), но, возможно, до начала каких -либо стилей/макета. |
styleAndLayoutStart | Когда происходит стиль/макет в рамке. Может быть полезен при выяснении длины работы стиля/макета при выяснении в других доступных временных метках. |
scripts | Множество элементов, содержащих информацию о атрибуции скрипта, вносящая вклад в INP страницы. |

blockingDuration
). Вся эта информация может многое рассказать вам о том, что делает взаимодействие медленным, но массив scripts
, который поверхность блоков буханки должен представлять особый интерес:
Ключ объекта атрибуции скрипта | Данные |
---|---|
invoker | Invoker. Это может варьироваться в зависимости от типа Invoker, описанного в следующем ряду. Примерами Invokers могут быть такие значения, как 'IMG#id.onload' , 'Window.requestAnimationFrame' или 'Response.json.then' . |
invokerType | Тип инвента. Может быть 'user-callback' , 'event-listener' , 'resolve-promise' , 'reject-promise' , 'classic-script' или 'module-script' . |
sourceURL | URL -адрес сценария, откуда происходил длинная анимационная кадра. |
sourceCharPosition | Позиция символа в сценарии, идентифицированную sourceURL . |
sourceFunctionName | Имя функции в идентифицированном сценарии. |
Каждая запись в этом массиве содержит данные, показанные в этой таблице, которые дают вам информацию о сценарии, который отвечал за медленное взаимодействие, и о том, как оно отвечало.
Измерить и определить общие причины медленных взаимодействий
Чтобы дать вам представление о том, как вы можете использовать эту информацию, это руководство теперь пройдет через то, как вы можете использовать данные буханки, появившиеся в библиотеке web-vitals
чтобы определить некоторые причины медленных взаимодействий.
Длительная продолжительность обработки
Продолжительность обработки взаимодействия - это время, которое необходимо для зарегистрированных обратных вызовов, обработанных зарегистрированным событием, для завершения и всего, что может произойти между ними. Высокая продолжительность обработки оказывается библиотекой веб-виталов:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {processingDuration} = attribution; // 512.5
});
Естественно думать, что основная причина медленного взаимодействия состоит в том, что ваш код обработчика мероприятий занимал слишком много времени, чтобы запустить, но это не всегда так! После того, как вы подтвердили, что это проблема, вы можете копать глубже с данными буханки:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {processingDuration} = attribution; // 512.5
// Get the longest script from LoAF covering `processingDuration`:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
if (script) {
// Get attribution for the long-running event handler:
const {invokerType} = script; // 'event-listener'
const {invoker} = script; // 'BUTTON#update.onclick'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Как вы можете видеть в предыдущем фрагменте кода, вы можете работать с данными Loaf, чтобы отследить точную причину взаимодействия с высокими значениями продолжительности обработки, включая:
- Элемент и его зарегистрированный слушатель событий.
- Файл сценария-и позиция символа в нем-содержит длительный код обработчика событий.
- Имя функции.
Этот тип данных бесценен. Вам больше не нужно выполнять работу, чтобы точно выяснить, какое взаимодействие - или какое из его обработчиков событий - отвечало за высокие значения продолжительности обработки. Кроме того, поскольку сторонние сценарии часто могут зарегистрировать свои собственные обработчики событий, вы можете определить, был ли ваш код, который был ответственным! Для кода, который у вас есть контроль, вы захотите изучить оптимизацию длинных задач .
Длинные входные задержки
В то время как длительные обработчики событий являются обычными, есть и другие части взаимодействия, которые следует учитывать. Одна часть происходит до продолжительности обработки, которая известна как задержка ввода . Это время, когда пользователь инициирует взаимодействие, до момента, как его обратные вызовы событий начинают работать и происходит, когда основной поток уже обрабатывает другую задачу. Сборка атрибуции библиотеки веб-виталов может сообщить вам о длине задержки ввода для взаимодействия:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
});
Если вы заметите, что некоторые взаимодействия имеют высокие задержки ввода, вам нужно выяснить, что происходит на странице во время взаимодействия, которое вызвало длительную задержку ввода, и это часто сводится к тому, произошло ли взаимодействие, когда страница загружалась, или после этого.
Было ли это во время загрузки страницы?
Основная поток часто бывает наиболее загруженной, поскольку страница загружается. В течение этого времени все виды задач подвергаются в очередь и обрабатываются, и если пользователь пытается взаимодействовать со страницей, в то время как вся эта работа происходит, это может задержать взаимодействие. Страницы, которые загружают много JavaScript, могут начать работу для компиляции и оценки сценариев, а также выполнения функций, которые поднимают страницу для взаимодействия с пользователем. Эта работа может мешать, если пользователь взаимодействует с этим действием, и вы можете выяснить, имеет ли это место для пользователей вашего веб -сайта:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
// Get the longest script from the first LoAF entry:
const loaf = attribution.longAnimationFrameEntries[0];
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
if (script) {
// Invoker types can describe if script eval blocked the main thread:
const {invokerType} = script; // 'classic-script' | 'module-script'
const {sourceLocation} = script; // 'https://example.com/app.js'
}
});
Если вы записываете эти данные в этой области и видите высокие задержки ввода и типы Invoker 'classic-script'
или 'module-script'
, то справедливо сказать, что сценарии на вашем сайте занимают много времени для оценки и блокируют основной теме достаточно долго, чтобы задержать взаимодействия. Вы можете сократить это время блокировки, разбив свои сценарии на более мелкие пакеты, отложите изначально неиспользованный код, который будет загружен в более поздний момент времени, и проверить ваш сайт для неиспользованного кода, который вы можете полностью удалить.
Was it after page load?
While input delays often occur while a page is loading, it's just as possible that they can occur after a page has loaded, due to an entirely different cause. Common causes of input delays after page load can be code that runs periodically due to an earlier setInterval
call, or even event callbacks that were queued to run earlier, and are still processing.
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
// Get the longest script from the first LoAF entry:
const loaf = attribution.longAnimationFrameEntries[0];
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
if (script) {
const {invokerType} = script; // 'user-callback'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
As is the case with troubleshooting high processing duration values, high input delays due to the causes mentioned earlier will give you detailed script attribution data. What is different, however, is that the invoker type will change based on the nature of the work that delayed the interaction:
-
'user-callback'
indicates the blocking task was fromsetInterval
,setTimeout
, or evenrequestAnimationFrame
. -
'event-listener'
indicates that the blocking task was from an earlier input that was queued and still processing. -
'resolve-promise'
and'reject-promise'
means that the blocking task was from some asynchronous work that was kicked off earlier, and resolved or rejected at a time when the user attempted to interact with the page, delaying the interaction.
In any case, the script attribution data will give you a sense of where to start looking, and whether the input delay was due to your own code, or that of a third-party script.
Long presentation delays
Presentation delays are the last mile of an interaction, and begin when the interaction's event handlers finish, up to the point at which the next frame was painted. They occur when the work in an event handler due to an interaction changes the visual state of the user interface. As with processing durations and input delays, the web-vitals library can tell you how long the presentation delay was for an interaction:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 113.32307691
});
If you record this data and see high presentation delays for interactions contributing to your website's INP, the culprits can vary, but here are a couple causes to be on the lookout for.
Expensive style and layout work
Long presentation delays may be expensive style recalculation and layout work that arises from a number of causes, including complex CSS selectors and large DOM sizes . You can measure the duration this work with the LoAF timings surfaced in the web-vitals library:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 113.32307691
// Get the longest script from the last LoAF entry:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
// Get necessary timings:
const {startTime} = loaf; // 2120.5
const {duration} = loaf; // 1002
// Figure out the ending timestamp of the frame (approximate):
const endTime = startTime + duration; // 3122.5
// Get the start timestamp of the frame's style/layout work:
const {styleAndLayoutStart} = loaf; // 3011.17692309
// Calculate the total style/layout duration:
const styleLayoutDuration = endTime - styleAndLayoutStart; // 111.32307691
if (script) {
// Get attribution for the event handler that triggered
// the long-running style and layout operation:
const {invokerType} = script; // 'event-listener'
const {invoker} = script; // 'BUTTON#update.onclick'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
LoAF won't tell you the duration of the style and layout work is for a frame, but it will tell you when it started. With this starting timestamp, you can use other data from LoAF to calculate an accurate duration of that work by determining the end time of the frame, and subtracting the start timestamp of the style and layout work from that.
Long-running requestAnimationFrame
callbacks
One potential cause of long presentation delays is excessive work done in a requestAnimationFrame
callback. The contents of this callback are executed after event handlers have finished running, but just prior to style recalculation and layout work.
These callbacks can take considerable time to complete if the work done within them is complex. If you suspect high presentation delay values are due to work you're doing with requestAnimationFrame
, you can use LoAF data surfaced by the web-vitals library to identify these scenarios:
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 543.1999999880791
// Get the longest script from the last LoAF entry:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
// Get the render start time and when style and layout began:
const {renderStart} = loaf; // 2489
const {styleAndLayoutStart} = loaf; // 2989.5999999940395
// Calculate the `requestAnimationFrame` callback's duration:
const rafDuration = styleAndLayoutStart - renderStart; // 500.59999999403954
if (script) {
// Get attribution for the event handler that triggered
// the long-running requestAnimationFrame callback:
const {invokerType} = script; // 'user-callback'
const {invoker} = script; // 'FrameRequestCallback'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
If you see that a significant portion of the presentation delay time is spent in a requestAnimationFrame
callback, ensure the work you're doing in these callbacks is limited to performing work that results in an actual update to the user interface. Any other work that doesn't touch the DOM or update styles will unnecessarily delay the next frame from being painted, so be careful!
Заключение
Field data is the best source of information you can draw on when it comes to understanding which interactions are problematic for actual users in the field. By relying on field data collection tools such as the web-vitals JavaScript library (or a RUM provider), you can be more confident about which interactions are most problematic, and then move on to reproducing problematic interactions in the lab and then go about fixing them.
Hero image from Unsplash , by Federico Respini .