Пользовательские метрики

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

Специальные метрики позволяют измерять аспекты взаимодействия с вашим сайтом, которые могут относиться только к нему, например:

  • Сколько времени требуется одностраничному приложению (SPA) для перехода с одной «страницы» на другую.
  • Сколько времени требуется странице для отображения данных, полученных из базы данных для вошедших в систему пользователей.
  • Сколько времени требуется приложению, отображаемому на стороне сервера (SSR), для гидратации .
  • Коэффициент попадания в кеш ресурсов, загруженных вернувшимися посетителями.
  • Задержка событий щелчка или клавиатуры в игре.

API для измерения пользовательских метрик

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

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

API наблюдателя за производительностью

Поддержка браузера

  • 52
  • 79
  • 57
  • 11

Источник

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

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

При создании PerformanceObserver передайте ему обратный вызов, который запускается всякий раз, когда отправляются новые записи производительности. Затем используйте метод observe() , чтобы сообщить наблюдателю, какие типы записей следует прослушивать, следующим образом:

// Catch errors that some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  const po = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      // Log the entry and all associated details.
      console.log(entry.toJSON());
    }
  });

  po.observe({type: 'some-entry-type'});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

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

Обратите внимание на записи, которые уже произошли

По умолчанию объекты PerformanceObserver могут наблюдать записи только по мере их появления. Это может вызвать проблемы, если вы хотите отложенно загружать код аналитики производительности, чтобы он не блокировал ресурсы с более высоким приоритетом.

Чтобы получить исторические записи, вызовите observe с флагом buffered , установленным в значение true . Затем браузер включает исторические записи из своего буфера записей производительности при первом вызове обратного вызова PerformanceObserver .

po.observe({
  type: 'some-entry-type',
  buffered: true,
});

Устаревшие API производительности, которых следует избегать

До API Performance Observer разработчики могли получать доступ к записям производительности, используя следующие методы, определенные в объекте performance . Мы не рекомендуем их использовать, поскольку они не позволяют прослушивать новые записи.

Кроме того, многие новые API (например, Long Tasks) не предоставляются объектом performance , а только PerformanceObserver . Поэтому, если вам не нужна совместимость с Internet Explorer, лучше избегать этих методов в своем коде и в дальнейшем использовать PerformanceObserver .

API синхронизации пользователя

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

// Record the time immediately before running a task.
performance.mark('myTask:start');
await doMyTask();

// Record the time immediately after running a task.
performance.mark('myTask:end');

// Measure the delta between the start and end of the task
performance.measure('myTask', 'myTask:start', 'myTask:end');

Хотя такие API, как Date.now() или performance.now() , предоставляют аналогичные возможности, API User Timing лучше интегрируется с инструментами повышения производительности. Например, Chrome DevTools визуализирует измерения пользовательского времени на панели «Производительность» , а многие поставщики аналитики автоматически отслеживают любые ваши измерения и отправляют данные о продолжительности на свой аналитический сервер.

Чтобы сообщать об измерениях пользовательского времени, зарегистрируйте PerformanceObserver для наблюдения за записями типа measure :

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  const po = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      // Log the entry and all associated details.
      console.log(entry.toJSON());
    }
  });

  // Start listening for `measure` entries.
  po.observe({type: 'measure', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

API длинных задач

Поддержка браузера

  • 58
  • 79
  • Икс
  • Икс

Источник

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

Каждый раз, когда вам нужно запустить дорогостоящий код или загрузить и выполнить большие сценарии, полезно отслеживать, не блокирует ли этот код основной поток. Фактически, многие метрики более высокого уровня создаются поверх самого API длинных задач (например, время взаимодействия (TTI) и общее время блокировки (TBT) ).

Чтобы определить, когда выполняются длительные задачи, зарегистрируйте PerformanceObserver для наблюдения за записями типа longtask :

// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  const po = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      // Log the entry and all associated details.
      console.log(entry.toJSON());
    }
  });
  // Start listening for `longtask` entries to be dispatched.
  po.observe({type: 'longtask', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

API синхронизации элементов

Поддержка браузера

  • 77
  • 79
  • Икс
  • Икс

Источник

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

В этих случаях используйте Element Timing API . API LCP фактически построен на основе API синхронизации элементов и добавляет автоматические отчеты о самом большом элементе с содержимым, но вы также можете создавать отчеты о других элементах, явно добавляя к ним атрибут elementtiming и регистрируя PerformanceObserver для наблюдения за типом записи element . .

<img elementtiming="hero-image" />
<p elementtiming="important-paragraph">This is text I care about.</p>
...
<script>
// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  const po = new PerformanceObserver((entryList) => {
    for (const entry of entryList.getEntries()) {
      // Log the entry and all associated details.
      console.log(entry.toJSON());
    }
  });
  // Start listening for `element` entries to be dispatched.
  po.observe({type: 'element', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}
</script>

API синхронизации событий

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

Метрика INP стала возможной благодаря API синхронизации событий . Этот API предоставляет ряд временных меток, которые возникают в течение жизненного цикла события, в том числе:

  • startTime : время, когда браузер получает событие.
  • processingStart : время, когда браузер может начать обработку обработчиков события.
  • processingEnd : время, когда браузер завершает выполнение всего синхронного кода, инициированного обработчиками событий для этого события.
  • duration : время (округленное до 8 мс по соображениям безопасности) между получением браузером события и возможностью отрисовки следующего кадра после завершения выполнения всего синхронного кода, инициированного обработчиками событий.

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

Следующий фрагмент кода показывает, как можно получить различные полезные данные для каждого взаимодействия, происходящего на странице:

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  const po = new PerformanceObserver((entryList) => {
    // Get the last interaction observed:
    const entries = Array.from(entryList.getEntries()).forEach((entry) => {
      // Get various bits of interaction data:
      const inputDelay = entry.processingStart - entry.startTime;
      const processingTime = entry.processingEnd - entry.processingStart;
      const duration = entry.duration;
      const eventType = entry.name;
      const target = entry.target || "(not set)"

      console.log("----- INTERACTION -----");
      console.log(`Input delay (ms): ${inputDelay}`);
      console.log(`Event handler time (ms): ${processingTime}`);
      console.log(`Total event duration (ms): ${duration}`);
      console.log(`Event type: ${eventType}`);
      console.log(target);
    });
  });

  // A durationThreshold of 16ms is necessary to surface more
  // interactions, since the default is 104ms. The minimum
  // durationThreshold is 16ms.
  po.observe({type: 'event', buffered: true, durationThreshold: 16});
} catch (error) {
  // Do nothing if the browser doesn't support this API.
}

API синхронизации ресурсов

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

  • initiatorType : как был получен ресурс, например, из тега <script> или <link> или из fetch() .
  • nextHopProtocol : протокол, используемый для получения ресурса, например h2 или quic .
  • encodedBodySize и decodedBodySize ]: размер ресурса в закодированной или декодированной форме (соответственно).
  • TransferSize : размер ресурса, который был фактически передан по сети. Когда ресурсы выполняются с использованием кеша, это значение может быть намного меньше, чем encodedBodySize , а в некоторых случаях оно может быть нулевым, если не требуется повторная проверка кеша.

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

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

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  const po = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      // If transferSize is 0, the resource was fulfilled via the cache.
      console.log(entry.name, entry.transferSize === 0);
    }
  });
  // Start listening for `resource` entries to be dispatched.
  po.observe({type: 'resource', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

Поддержка браузера

  • 57
  • 12
  • 58
  • 15

Источник

API синхронизации навигации аналогичен API синхронизации ресурсов, но он сообщает только о запросах навигации . Тип записи navigation также аналогичен типу записи resource , но он содержит некоторую дополнительную информацию , специфичную только для запросов навигации (например, при возникновении событий DOMContentLoaded и load ).

Одна метрика, которую многие разработчики отслеживают, чтобы понять время ответа сервера, время до первого байта (TTFB) , доступна через метку времени responseStart в API синхронизации навигации.

// Catch errors since  browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  const po = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      // If transferSize is 0, the resource was fulfilled using the cache.
      console.log('Time to first byte', entry.responseStart);
    }
  });
  // Start listening for `navigation` entries to be dispatched.
  po.observe({type: 'navigation', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

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

Время запуска сервис-воркера для указанного запроса навигации можно определить по разнице между entry.responseStart и entry.workerStart следующим образом:

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  const po = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      console.log('Service Worker startup time:',
          entry.responseStart - entry.workerStart);
    }
  });
  // Start listening for `navigation` entries to be dispatched.
  po.observe({type: 'navigation', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

API синхронизации сервера

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

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

Чтобы указать данные синхронизации сервера в ваших ответах, используйте заголовок ответа Server-Timing . Вот пример:

HTTP/1.1 200 OK

Server-Timing: miss, db;dur=53, app;dur=47.2

Затем со своих страниц вы можете прочитать эти данные как о resource , так и о записях navigation из API-интерфейсов синхронизации ресурсов и времени навигации.

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  const po = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      // Logs all server timing data for this response
      console.log('Server Timing', entry.serverTiming);
    }
  });
  // Start listening for `navigation` entries to be dispatched.
  po.observe({type: 'navigation', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}