Как устранять неполадки с производительностью в реальных условиях

Как сопоставить данные об эффективности со сведениями для отладки, чтобы выявлять и устранять проблемы, с которыми сталкиваются пользователи

Google предлагает два типа инструментов для отслеживания эффективности и устранения неполадок:

  • Лабораторные инструменты. Такие инструменты, как Lighthouse, загружают страницу в смоделированной среде, которая может имитировать различные условия, например медленную сеть и мобильное устройство низкого класса.
  • Инструменты для сбора данных в реальных условиях. К ним относятся, например, отчет об удобстве использования в браузере Chrome (CrUX), который основан на агрегированных данных реальных пользователей Chrome. (Обратите внимание, что данные, которые предоставляют такие инструменты, как PageSpeed Insights и Search Console, берутся из отчета CrUX.)

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

Данные CrUX лучше отражают реальную эффективность страницы, но знание показателей CrUX вряд ли поможет вам понять, как улучшить эффективность.

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

Возникает важный вопрос: как получить от реальных пользователей сведения для отладки Core Web Vitals и других показателей эффективности?

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

API для атрибуции и отладки

Cumulative Layout Shift (CLS)

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

Рассмотрим следующий отчет из PageSpeed Insights:

Отчет PageSpeed Insights с разными значениями CLS
PageSpeed Insights показывает как экспериментальные, так и полевые данные, если они доступны, и они могут отличаться.

Значения CLS, полученные в лабораторных условиях (Lighthouse) и в реальных условиях (данные CrUX), могут сильно различаться. Это объясняется тем, что на странице может быть много интерактивного контента, который не используется при тестировании в Lighthouse.

Но даже если вы понимаете, что взаимодействие пользователя влияет на данные полей, вам все равно нужно знать, какие элементы на странице смещаются, чтобы получить оценку 0,28 на 75-м процентиле. Интерфейс LayoutShiftAttribution позволяет это сделать.

Как получить данные об атрибуции смещений макета

Интерфейс LayoutShiftAttribution доступен в каждой записи layout-shift, которую создает API нестабильности макета.

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

Ниже приведен пример кода, который регистрирует каждое смещение макета, а также элементы, которые были смещены:

new PerformanceObserver((list) => {
  for (const {value, startTime, sources} of list.getEntries()) {
    // Log the shift amount and other entry info.
    console.log('Layout shift:', {value, startTime});
    if (sources) {
      for (const {node, curRect, prevRect} of sources) {
        // Log the elements that shifted.
        console.log('  Shift source:', node, {curRect, prevRect});
      }
    }
  }
}).observe({type: 'layout-shift', buffered: true});

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

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

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

Следующий код принимает список записей layout-shift, которые повлияли на CLS, и возвращает самый большой исходный элемент из самого большого сдвига:

function getCLSDebugTarget(entries) {
  const largestEntry = entries.reduce((a, b) => {
    return a && a.value > b.value ? a : b;
  });
  if (largestEntry && largestEntry.sources && largestEntry.sources.length) {
    const largestSource = largestEntry.sources.reduce((a, b) => {
      return a.node && a.previousRect.width * a.previousRect.height >
          b.previousRect.width * b.previousRect.height ? a : b;
    });
    if (largestSource) {
      return largestSource.node;
    }
  }
}

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

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

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

Другие метаданные, которые могут быть полезны для сбора вместе с самым большим элементом источника сдвига:

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

Largest Contentful Paint (LCP)

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

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

Такое может произойти по следующим причинам:

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

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

Как определить элемент, который может стать LCP

Чтобы определить элемент-кандидат на LCP в JavaScript, можно использовать Largest Contentful Paint API – тот же API, который вы используете для определения значения времени LCP.

При анализе записей largest-contentful-paint вы можете определить текущий элемент-кандидат LCP, посмотрев свойство element последней записи:

new PerformanceObserver((list) => {
  const entries = list.getEntries();
  const lastEntry = entries[entries.length - 1];

  console.log('LCP element:', lastEntry.element);
}).observe({type: 'largest-contentful-paint', buffered: true});

Определив элемент-кандидат LCP, вы можете отправить его в инструмент аналитики вместе со значением показателя. Как и в случае с CLS, это поможет вам определить, какие элементы следует оптимизировать в первую очередь.

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

Взаимодействие до следующей отрисовки (INP)

Вот какие данные нужно собирать в полевых условиях для INP:

  1. С каким элементом было выполнено взаимодействие
  2. тип взаимодействия;
  3. Когда произошло взаимодействие

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

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

В приведенном ниже коде регистрируется целевой элемент и время записи INP.

function logINPDebugInfo(inpEntry) {
  console.log('INP target element:', inpEntry.target);
  console.log('INP interaction type:', inpEntry.name);
  console.log('INP time:', inpEntry.startTime);
}

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

Использование с библиотекой JavaScript web-vitals

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

Начиная с версии 3, библиотека JavaScript web-vitals включает сборку атрибуции, которая предоставляет всю эту информацию, а также несколько дополнительных сигналов.

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

import {onCLS, onINP, onLCP} from 'web-vitals/attribution';

function sendToGoogleAnalytics({name, value, id, attribution}) {
  const eventParams = {
    metric_value: value,
    metric_id: id,
  }

  switch (name) {
    case 'CLS':
      eventParams.debug_target = attribution.largestShiftTarget;
      break;
    case 'LCP':
      eventParams.debug_target = attribution.element;
      break;
    case 'INP':
      eventParams.debug_target = attribution.interactionTarget;
      break;
  }

  // Assumes the global `gtag()` function exists, see:
  // https://developers.google.com/analytics/devguides/collection/ga4
  gtag('event', name, eventParams);
}

onCLS(sendToGoogleAnalytics);
onLCP(sendToGoogleAnalytics);
onINP(sendToGoogleAnalytics);

Этот код предназначен для Google Аналитики, но его можно адаптировать и для других инструментов аналитики.

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

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

В сборке атрибуции web-vitals доступны дополнительные сведения об атрибуции, как показано в следующем примере для INP:

import {onCLS, onINP, onLCP} from 'web-vitals/attribution';

function sendToGoogleAnalytics({name, value, id, attribution}) {
  const eventParams = {
    metric_value: value,
    metric_id: id,
  }

  switch (name) {
    case 'INP':
      eventParams.debug_target = attribution.interactionTarget;
      eventParams.debug_type = attribution.interactionType;
      eventParams.debug_time = attribution.interactionTime;
      eventParams.debug_load_state = attribution.loadState;
      eventParams.debug_interaction_delay = Math.round(attribution.inputDelay);
      eventParams.debug_processing_duration = Math.round(attribution.processingDuration);
      eventParams.debug_presentation_delay =  Math.round(attribution.presentationDelay);
      break;

    // Additional metric logic...
  }

  // Assumes the global `gtag()` function exists, see:
  // https://developers.google.com/analytics/devguides/collection/ga4
  gtag('event', name, eventParams);
}

onCLS(sendToGoogleAnalytics);
onLCP(sendToGoogleAnalytics);
onINP(sendToGoogleAnalytics);

Полный список сигналов отладки приведен в документации по атрибуции web-vitals.

Создание отчетов и визуализация данных

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

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

Для GA4 есть отдельная статья о том, как запрашивать и визуализировать данные с помощью BigQuery.

Сводка

Надеемся, что эта статья помогла вам понять, как использовать существующие API производительности и библиотеку web-vitals для получения сведений для отладки, которые помогут диагностировать производительность на основе реальных посещений пользователей. Хотя в этом руководстве основное внимание уделяется показателям Core Web Vitals, описанные здесь принципы также применимы к отладке любых показателей эффективности, которые можно измерить с помощью JavaScript.

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

Если вам не хватает информации или функций в API, чтобы отлаживать эти показатели, отправьте отзыв на адрес web-vitals-feedback@googlegroups.com.