Оптимизация INP: поиск проблемных мест у пользователей

Содержание

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

Но иногда этого бывает недостаточно. Бывает, что локально вроде всё ок, всё поправили, но INP на дашбордах RUM всё ещё не в зелёной зоне.

Как узнать, в чём же проблема с INP у реальных пользователей?

Нужно начать собирать больше данных: не только финальное значение метрики INP, но и контекст вокруг него.

Attribution Data

Если для сбора метрик используется npm пакет web-vitals, то сделать это будет очень просто.

Допустим, сейчас INP мы собираем как-то вот так:

// импортируем метод для сбора INP
import { onINP } from 'web-vitals';

// описываем, куда сохранить значение метрики
const sendMetricToBackend = (metric) => {
    fetch(endpointUrl, {
        method: 'POST',
        body: JSON.stringify({
            name: 'inp',
            value: metric.value,
        }),
    });
};

// передаём наш колбек в метод
onINP(sendMetricToBackend);

Далее с помощью нехитрых манипуляций делаем следующее:

// импортируем метод не из корня пакета,
// а из директории attribution
import { onINP } from 'web-vitals/attribution';

// так же описываем, куда сохранить значение метрики,
// только данных теперь у нас стало больше
const sendMetricToBackend = (metric) => {
    const {
        value,
        attribution: {
            // тип интеракции ('pointer' | 'keyboard')
            interactionType,
            // селектор элемента, с которым пользователь контактировал,
            // когда интеракция началась;
            // может быть равен пустой строке, если элемент удалён из DOM
            interactionTarget,
            // ссылка на ноду элемента, с которым пользователь контактировал,
            // когда интеракция началась;
            // может быть равен undefined, если элемент удалён из DOM
            interactionTargetElement,
            // значение inputDelay
            inputDelay,
            // значение processingDuration
            processingDuration,
            // значение presentationDelay
            presentationDelay,
            // статус загрузки документа в момент совершения интеракции
            loadState,
        },
    } = metric;

    fetch(endpointUrl, {
        method: 'POST',
        body: JSON.stringify({
            name: 'inp',
            value,
            interactionType,
            interactionTarget,
            inputDelay,
            processingDuration,
            presentationDelay,
            loadState,
        }),
    });
};

// передаём наш колбек в метод
onINP(sendMetricToBackend);

Таким образом, можно узнать, какие элементы вызывают высокий INP, когда реальные пользователи с ними взаимодействуют. Также, имея данные об inputDelay, processingDuration, presentationDelay, можно понять, в чём именно проблема: основной поток занят чем-то ещё, долгая обработка события или что-то блокирует отрисовку. А loadState подскажет, в каком состоянии находилась страница: была она уже загружена и интерактивна или ещё нет.

Более подробную документацию по attribution методам можно найти в README пакета web-vitals.

Если метрики собираются напрямую из Performance APIs, то реализовать сбор attribution data тоже можно — нужно будет только больше приседаний сделать. Реализацию можно подсмотреть в пакете web-vitals.