Как web-vitals использует PerformanceObserver внутри

Библиотека Web Vitals в JavaScript предоставляет удобный способ измерять ключевые показатели пользовательского опыта, такие как Largest Contentful Paint (LCP), First Input Delay (FID), Cumulative Layout Shift (CLS) и другие. Для получения этих метрик в реальном времени используется встроенный браузерный API PerformanceObserver, который позволяет подписываться на различные типы событий производительности и получать их данные асинхронно.

Подключение и инициализация PerformanceObserver

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

const observer = new PerformanceObserver((list) => {
  const entries = list.getEntries();
  entries.forEach((entry) => {
    console.log(entry);
  });
});

Важно указывать entryTypes, чтобы наблюдатель подписался только на нужные события:

observer.observe({ type: 'largest-contentful-paint', buffered: true });

Параметр buffered: true гарантирует, что PerformanceObserver получит уже произошедшие события, которые браузер успел записать до начала наблюдения.

Использование PerformanceObserver для LCP

Largest Contentful Paint (LCP) измеряет время, когда на странице отображается самый крупный элемент контента. Web Vitals регистрирует событие LCP через PerformanceObserver с типом "largest-contentful-paint":

import { onLCP } from 'web-vitals';

onLCP((metric) => {
  console.log('LCP:', metric.value);
});

Внутри onLCP библиотека создаёт PerformanceObserver, который отслеживает все записи типа largest-contentful-paint. Как только событие фиксируется, вызывается callback, передавая объект метрики с ключевыми свойствами:

  • value — время в миллисекундах до отображения элемента
  • entries — массив записей PerformanceEntry, связанных с LCP
  • id — уникальный идентификатор метрики

First Input Delay и PerformanceObserver

First Input Delay (FID) отражает задержку реакции страницы на первый ввод пользователя. Для измерения FID Web Vitals использует тип first-input:

import { onFID } from 'web-vitals';

onFID((metric) => {
  console.log('FID:', metric.value);
});

Внутри наблюдателя создаются записи типа PerformanceEventTiming. Ключевые свойства:

  • startTime — время события
  • processingStart — момент начала обработки события
  • name — тип события (click, keydown и др.)

Web Vitals вычисляет разницу между processingStart и startTime, чтобы определить задержку.

Cumulative Layout Shift и механизм наблюдения

Cumulative Layout Shift (CLS) оценивает визуальную стабильность страницы. CLS основан на типе событий "layout-shift". Каждое смещение фиксируется с помощью PerformanceObserver:

import { onCLS } from 'web-vitals';

onCLS((metric) => {
  console.log('CLS:', metric.value);
});

Web Vitals фильтрует записи, исключая смещения, вызванные пользовательскими взаимодействиями (entry.hadRecentInput === false), и суммирует значения для расчета CLS.

Внутренние особенности работы Web Vitals с PerformanceObserver

  1. Буферизация событий: Использование параметра buffered: true позволяет библиотеке получать события, которые произошли до инициализации наблюдателя. Это критично для LCP и CLS, чтобы данные не терялись при динамической загрузке скриптов.

  2. Отслеживание нескольких типов одновременно: Web Vitals может запускать несколько PerformanceObserver параллельно — для LCP, FID и CLS — без конфликта, благодаря независимым callback-функциям.

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

  4. Обработка записей по пакетам: PerformanceObserver вызывает callback с массивом записей, а Web Vitals обрабатывает их последовательно, выбирая релевантную информацию для каждой метрики и отбрасывая лишние события.

Пример комплексного наблюдения

import { onCLS, onFID, onLCP } from 'web-vitals';

onCLS((metric) => console.log('CLS', metric.value));
onFID((metric) => console.log('FID', metric.value));
onLCP((metric) => console.log('LCP', metric.value));

Библиотека скрывает детали создания и управления PerformanceObserver, предоставляя простой и унифицированный API. Тем не менее, понимание того, что каждый вызов Web Vitals создает внутренний наблюдатель и подписывается на определенные типы событий, помогает глубже осознать, как метрики собираются в реальном времени без потери точности.


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