Wskaźniki niestandardowe

Wskaźniki zorientowane na użytkownika, które można mierzyć uniwersalnie w dowolnej witrynie, mają dużą wartość. Te dane umożliwiają:

  • Poznawanie wrażeń użytkowników korzystających z internetu.
  • Porównaj swoją witrynę z witryną konkurencji.
  • Śledź przydatne dane w narzędziach analitycznych bez konieczności pisania kodu niestandardowego.

Uniwersalne dane stanowią dobrą podstawę, ale w wielu przypadkach musisz mierzyć więcej niż tylko te dane, aby w pełni poznać wrażenia użytkowników w Twojej witrynie.

Dane niestandardowe umożliwiają pomiar aspektów związanych z użytkowaniem witryny, które mogą dotyczyć tylko Twojej witryny, np.:

  • Czas, jaki zajmuje aplikacji jednostronicowej przejście z jednej „strony” na drugą.
  • Czas, jaki upływa od momentu wyświetlenia strony do momentu wyświetlenia danych pobranych z bazy danych dla zalogowanych użytkowników.
  • Czas potrzebny aplikacji renderowanej po stronie serwera (SSR) na hydratację.
  • Współczynnik trafień w pamięci podręcznej w przypadku zasobów wczytywanych przez powracających użytkowników.
  • Opóźnienie zdarzeń kliknięcia lub zdarzeń klawiatury w grze.

Interfejsy API do pomiaru danych niestandardowych

Deweloperzy stron internetowych nie mieli dotychczas wielu interfejsów API niskiego poziomu do pomiaru wydajności, więc musieli uciekać się do sztuczek, aby sprawdzić, czy witryna działa prawidłowo.

Można na przykład sprawdzić, czy wątek główny jest zablokowany z powodu długotrwałych zadań JavaScript, uruchamiając pętlę requestAnimationFrame i obliczając różnicę między poszczególnymi klatkami. Jeśli różnica jest znacznie dłuższa niż liczba klatek na sekundę wyświetlacza, możesz zgłosić to jako długie zadanie. Nie zalecamy jednak takich sztuczek, ponieważ same wpływają na wydajność (np. wyczerpują baterię).

Pierwsza zasada skutecznego pomiaru wydajności polega na tym, aby techniki pomiaru wydajności nie powodowały problemów z wydajnością. Dlatego w przypadku wszystkich niestandardowych danych, które mierzysz w swojej witrynie, najlepiej jest w miarę możliwości używać jednego z tych interfejsów API.

Performance Observer API

Browser Support

  • Chrome: 52.
  • Edge: 79.
  • Firefox: 57.
  • Safari: 11.

Source

Interfejs Performance Observer API to mechanizm, który zbiera i wyświetla dane ze wszystkich innych interfejsów Performance API omówionych na tej stronie. Zrozumienie tego pojęcia ma kluczowe znaczenie dla uzyskania dobrych danych.

Możesz użyć PerformanceObserver, aby pasywnie subskrybować zdarzenia związane z wydajnością. Dzięki temu wywołania zwrotne interfejsu API są uruchamiane w okresach bezczynności, co oznacza, że zwykle nie wpływają na wydajność strony.

Aby utworzyć PerformanceObserver, przekaż do niego wywołanie zwrotne, które ma być uruchamiane za każdym razem, gdy wysyłane są nowe wpisy dotyczące wydajności. Następnie poinformuj obserwatora, jakich typów wpisów ma szukać, używając metody observe():

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'});

W sekcjach poniżej znajdziesz listę wszystkich typów wpisów dostępnych do obserwacji. W nowszych przeglądarkach możesz sprawdzić, jakie typy wpisów są dostępne, za pomocą statycznej właściwości PerformanceObserver.supportedEntryTypes.

Obserwowanie wpisów, które już się pojawiły

Domyślnie obiekty PerformanceObserver mogą obserwować wpisy tylko w momencie ich wystąpienia. Może to powodować problemy, jeśli chcesz leniwie wczytywać kod analityki wydajności, aby nie blokował on zasobów o wyższym priorytecie.

Aby uzyskać wpisy historyczne (po ich wystąpieniu), ustaw flagę buffered na true, gdy wywołujesz observe(). Przeglądarka uwzględni wpisy historyczne z bufora wpisów dotyczących wydajności przy pierwszym wywołaniu funkcji zwrotnej PerformanceObserver, aż do maksymalnego rozmiaru bufora dla danego typu.

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

Starsze interfejsy API dotyczące skuteczności, których należy unikać

Przed wprowadzeniem interfejsu Performance Observer API deweloperzy mogli uzyskiwać dostęp do wpisów dotyczących wydajności za pomocą tych 3 metod zdefiniowanych w obiekcie performance:

Te interfejsy API są nadal obsługiwane, ale nie zalecamy ich używania, ponieważ nie umożliwiają one nasłuchiwania, kiedy pojawiają się nowe wpisy. Dodatkowo wiele nowych interfejsów API (np. largest-contentful-paint) nie jest dostępnych w obiekcie performance, tylko w obiekcie PerformanceObserver.

Jeśli nie potrzebujesz zgodności z Internet Explorerem, lepiej unikać tych metod w kodzie i używać PerformanceObserver.

User Timing API

Browser Support

  • Chrome: 28.
  • Edge: 12.
  • Firefox: 38.
  • Safari: 11.

Source

User Timing API to ogólny interfejs API do pomiaru wskaźników opartych na czasie. Umożliwia dowolne oznaczanie punktów w czasie, a następnie mierzenie czasu między nimi.

// 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');

Interfejsy API, takie jak Date.now() czy performance.now(), zapewniają podobne możliwości, ale zaletą interfejsu User Timing API jest to, że dobrze integruje się z narzędziami do pomiaru wydajności. Na przykład Narzędzia deweloperskie w Chrome wizualizują pomiary czasu użytkownika na panelu Wydajność, a wielu dostawców usług analitycznych automatycznie śledzi wszystkie pomiary i wysyła dane o czasie trwania do swojego zaplecza analitycznego.

Aby raportować pomiary czasu działania użytkownika, możesz użyć interfejsu PerformanceObserver i zarejestrować się w celu obserwowania wpisów typu measure:

// 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 to be dispatched.
po.observe({type: 'measure', buffered: true});

Long Tasks API

Browser Support

  • Chrome: 58.
  • Edge: 79.
  • Firefox: not supported.
  • Safari: not supported.

Source

Interfejs Long Tasks API przydaje się do określania, kiedy wątek główny przeglądarki jest zablokowany na wystarczająco długo, aby wpłynąć na liczbę klatek na sekundę lub opóźnienie działania. Interfejs API będzie zgłaszać wszystkie zadania, które trwają dłużej niż 50 milisekund.

Gdy musisz uruchomić kod wymagający dużych zasobów lub wczytać i wykonać duże skrypty, warto śledzić, czy ten kod blokuje wątek główny. Wiele wskaźników wyższego poziomu jest opartych na interfejsie Long Tasks API (np. czas do pełnej interaktywności (TTI)całkowity czas blokowania (TBT)).

Aby określić, kiedy występują długie zadania, możesz użyć interfejsu PerformanceObserver i zarejestrować się, aby obserwować wpisy typu longtask:

// 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});

Long Animation Frames API

Browser Support

  • Chrome: 123.
  • Edge: 123.
  • Firefox: not supported.
  • Safari: not supported.

Source

Long Animation Frames API to nowa wersja interfejsu Long Tasks API, która analizuje długie klatki – a nie długie zadania – trwające ponad 50 milisekund. Rozwiązuje to niektóre niedociągnięcia interfejsu Long Tasks API, w tym lepsze przypisywanie atrybucji i szerszy zakres potencjalnie problematycznych opóźnień.

Aby określić, kiedy występują długie klatki, możesz użyć interfejsu PerformanceObserver i zarejestrować się, aby obserwować wpisy typu long-animation-frame:

// 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 `long-animation-frame` entries to be dispatched.
po.observe({type: 'long-animation-frame', buffered: true});

Element Timing API

Browser Support

  • Chrome: 77.
  • Edge: 79.
  • Firefox: not supported.
  • Safari: not supported.

Source

Wskaźnik największego wyrenderowania treści (LCP) jest przydatny, gdy chcesz wiedzieć, kiedy na ekranie pojawił się największy obraz lub blok tekstu, ale w niektórych przypadkach możesz chcieć zmierzyć czas renderowania innego elementu.

W takich przypadkach użyj interfejsu Element Timing API. Interfejs LCP API jest w rzeczywistości oparty na interfejsie Element Timing API i dodaje automatyczne raportowanie największego elementu treści, ale możesz też raportować inne elementy, dodając do nich atrybut elementtiming i rejestrując PerformanceObserver do obserwowania typu wpisu element.

<img elementtiming="hero-image" />
<p elementtiming="important-paragraph">This is text I care about.</p>
<!-- ... -->

<script>
  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});
</script>

Event Timing API

Browser Support

  • Chrome: 76.
  • Edge: 79.
  • Firefox: 89.
  • Safari: 26.2.

Source

Wskaźnik interakcja do kolejnego wyrenderowania (INP) ocenia ogólną responsywność strony na podstawie obserwacji wszystkich kliknięć, dotknięć i interakcji z klawiaturą w całym okresie jej działania. Wartość INP strony to najczęściej interakcja, która trwała najdłużej od momentu rozpoczęcia interakcji przez użytkownika do momentu, w którym przeglądarka wyrenderowała kolejną klatkę pokazującą wizualny efekt danych wprowadzonych przez użytkownika.

Dane INP są możliwe dzięki interfejsowi Event Timing API. Ten interfejs API udostępnia kilka sygnatur czasowych, które występują w cyklu życia zdarzenia, m.in.:

  • startTime: czas, w którym przeglądarka otrzymała zdarzenie.
  • processingStart: czas, w którym przeglądarka może rozpocząć przetwarzanie modułów obsługi zdarzeń.
  • processingEnd: czas, w którym przeglądarka kończy wykonywanie całego synchronicznego kodu zainicjowanego przez obsługę zdarzeń dla tego zdarzenia.
  • duration: czas (zaokrąglony do 8 milisekund ze względów bezpieczeństwa) od momentu otrzymania zdarzenia przez przeglądarkę do momentu, w którym może ona narysować kolejną klatkę po zakończeniu wykonywania całego kodu synchronicznego zainicjowanego przez moduły obsługi zdarzeń.

Poniższy przykład pokazuje, jak używać tych wartości do tworzenia pomiarów niestandardowych:

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 presentationDelay = entry.startTime + entry.duration - entry.processingEnd;
    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 processing time (ms): ${processingTime}`);
    console.log(`Presentation delay (ms): ${presentationDelay}`);
    console.log(`Total event duration (ms): ${duration}`);
    console.log(`Event type: ${eventType}`);
    console.log(target);
  });
});

// A durationThreshold of 16ms is necessary to include more
// interactions, since the default is 104ms. The minimum
// durationThreshold is 16ms.
po.observe({type: 'event', buffered: true, durationThreshold: 16});

Resource Timing API

Browser Support

  • Chrome: 29.
  • Edge: 12.
  • Firefox: 35.
  • Safari: 11.

Source

Interfejs Resource Timing API zapewnia deweloperom szczegółowe informacje o tym, jak załadowano zasoby konkretnej strony. Mimo nazwy interfejsu API informacje, które udostępnia, nie ograniczają się tylko do danych o czasie (chociaż jest ich sporo). Inne dane, do których możesz mieć dostęp, to:

  • initiatorType: sposób pobrania zasobu, np. z tagu <script> lub <link> albo z wywołania fetch().
  • nextHopProtocol: protokół używany do pobierania zasobu, np. h2 lub quic.
  • encodedBodySize/decodedBodySize]: rozmiar zasobu w postaci zakodowanej lub zdekodowanej (odpowiednio).
  • transferSize: rozmiar zasobu, który został faktycznie przesłany przez sieć. Gdy zasoby są pobierane z pamięci podręcznej, ta wartość może być znacznie mniejsza niż encodedBodySize, a w niektórych przypadkach może wynosić zero (jeśli nie jest wymagana ponowna weryfikacja pamięci podręcznej).

Za pomocą właściwości transferSize wpisów dotyczących czasu wczytywania zasobów możesz mierzyć dane odsetka trafień w pamięci podręcznej lub całkowitego rozmiaru zasobów w pamięci podręcznej. Może to być przydatne do zrozumienia, jak strategia buforowania zasobów wpływa na skuteczność w przypadku powracających użytkowników.

W tym przykładzie rejestrowane są wszystkie zasoby, o które strona wysyła żądanie, oraz informacja o tym, czy każde żądanie zostało zrealizowane przez pamięć podręczną.

// 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(entry.name, entry.transferSize === 0);
  }
});

// Start listening for `resource` entries to be dispatched.
po.observe({type: 'resource', buffered: true});

Browser Support

  • Chrome: 57.
  • Edge: 12.
  • Firefox: 58.
  • Safari: 15.

Source

Interfejs Navigation Timing API jest podobny do interfejsu Resource Timing API, ale raportuje tylko żądania nawigacji. Typ wpisu navigation jest też podobny do typu wpisu resource, ale zawiera pewne dodatkowe informacje dotyczące tylko żądań nawigacyjnych (np. gdy uruchamiają się zdarzenia DOMContentLoadedload).

Jeden z rodzajów danych, które wielu programistów śledzi, aby poznać czas odpowiedzi serwera (czas do pierwszego bajta (TTFB)), jest dostępny w interfejsie Navigation Timing API, a konkretnie w postaci sygnatury czasowej responseStart.

// 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});

Kolejną wartością, na której może zależeć deweloperom korzystającym z usługi Service Worker, jest czas uruchamiania tej usługi w przypadku żądań nawigacji. Jest to czas, jaki przeglądarka potrzebuje na uruchomienie wątku service workera, zanim zacznie przechwytywać zdarzenia pobierania.

Czas uruchomienia service workera w przypadku konkretnego żądania nawigacji można określić na podstawie różnicy między wartościami entry.responseStartentry.workerStart.

// 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});

Server Timing API

Browser Support

  • Chrome: 65.
  • Edge: 79.
  • Firefox: 61.
  • Safari: 16.4.

Source

Server Timing API umożliwia przekazywanie do przeglądarki danych o czasie trwania konkretnych żądań z serwera za pomocą nagłówków odpowiedzi. Możesz na przykład podać, ile czasu zajęło wyszukanie danych w bazie danych w przypadku konkretnego żądania. Może to być przydatne przy debugowaniu problemów z wydajnością spowodowanych powolnym działaniem serwera.

W przypadku deweloperów korzystających z usług analitycznych innych firm interfejs Server Timing API jest jedynym sposobem na powiązanie danych o wydajności serwera z innymi wskaźnikami biznesowymi, które mogą być mierzone przez te narzędzia analityczne.

Aby określić dane o czasie działania serwera w odpowiedziach, możesz użyć nagłówka odpowiedzi Server-Timing. Oto przykład.

HTTP/1.1 200 OK

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

Następnie możesz odczytać te dane ze swoich stron w przypadku wpisów resource lub navigation z interfejsów API Resource Timing i Navigation Timing.

// 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});