Debuguj wydajność w terenie

Dowiedz się, jak przypisywać dane o skuteczności do informacji na potrzeby debugowania, aby za pomocą statystyk identyfikować i rozwiązywać problemy użytkowników.

Google udostępnia 2 kategorie narzędzi do pomiaru skuteczności i debugowania:

  • Narzędzia laboratoryjne: narzędzia takie jak Lighthouse, w których strona jest wczytywana w symulowanym środowisku, które może naśladować różne warunki (np. wolną sieć i urządzenie mobilne z niższej półki).
  • Narzędzia do pomiarów w terenie: narzędzia takie jak Raport na temat użytkowania Chrome (CrUX), który jest oparty na zbiorczych danych o rzeczywistych użytkownikach Chrome. (Pamiętaj, że dane z pól raportowane przez narzędzia takie jak PageSpeed Insights i Search Console pochodzą z danych CrUX).

Narzędzia polowe dostarczają dokładniejszych danych, które odzwierciedlają rzeczywiste wrażenia użytkowników, ale narzędzia laboratoryjne często lepiej pomagają w identyfikowaniu i rozwiązywaniu problemów.

Dane CrUX lepiej odzwierciedlają rzeczywistą wydajność strony, ale znajomość wyników CrUX raczej nie pomoże Ci ustalić, jak poprawić wydajność.

Lighthouse z kolei zidentyfikuje problemy i poda konkretne sugestie dotyczące poprawy. Lighthouse będzie jednak podawać sugestie tylko w przypadku problemów z wydajnością, które wykryje podczas wczytywania strony. Nie wykrywa problemów, które pojawiają się tylko w wyniku interakcji użytkownika, np. przewijania lub klikania przycisków na stronie.

Pojawia się więc ważne pytanie: jak uzyskać informacje na potrzeby debugowania Core Web Vitals lub innych wskaźników skuteczności od rzeczywistych użytkowników?

W tym poście szczegółowo wyjaśnimy, których interfejsów API możesz używać do zbierania dodatkowych informacji na potrzeby debugowania każdego z obecnych wskaźników Core Web Vitals, i podamy pomysły na to, jak rejestrować te dane w używanym narzędziu analitycznym.

Interfejsy API do atrybucji i debugowania

Skumulowane przesunięcie układu (CLS)

Ze wszystkich podstawowych wskaźników internetowych CLS jest prawdopodobnie tym, w przypadku którego zbieranie informacji do debugowania w terenie jest najważniejsze. CLS jest mierzony przez cały okres życia strony, więc sposób, w jaki użytkownik wchodzi z nią w interakcję (jak daleko przewija stronę, co klika itp.), może mieć znaczący wpływ na to, czy występują przesunięcia układu i które elementy się przesuwają.

Spójrz na ten raport z PageSpeed Insights:

Raport PageSpeed Insights z różnymi wartościami CLS
PageSpeed Insights wyświetla dane terenowe i laboratoryjne, jeśli są dostępne, i mogą się one różnić

Wartości CLS zgłaszane przez narzędzie laboratoryjne (Lighthouse) i wartości CLS z danych terenowych (dane raportu na temat użytkowania Chrome) znacznie się od siebie różnią. Jest to zrozumiałe, jeśli weźmiesz pod uwagę, że strona może zawierać dużo interaktywnych treści, które nie są używane podczas testowania w Lighthouse.

Nawet jeśli wiesz, że interakcja użytkownika wpływa na dane pól, nadal musisz wiedzieć, które elementy na stronie przesuwają się, aby uzyskać wynik 0,28 w 75 percentylu. Umożliwia to interfejs LayoutShiftAttribution.

Uzyskiwanie atrybucji przesunięcia układu

Interfejs LayoutShiftAttribution jest udostępniany w każdym wpisie layout-shift, który emituje interfejs Layout Instability API.

Szczegółowe wyjaśnienie obu tych interfejsów znajdziesz w artykule Debugowanie przesunięć układu. Na potrzeby tego posta najważniejsze jest to, że jako deweloper możesz obserwować każde przesunięcie układu, które następuje na stronie, a także to, które elementy się przesuwają.

Oto przykładowy kod, który rejestruje każde przesunięcie układu oraz elementy, które uległy przesunięciu:

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

Prawdopodobnie nie jest praktyczne mierzenie i wysyłanie danych do narzędzia analitycznego w przypadku każdego przesunięcia układu, ale monitorując wszystkie przesunięcia, możesz śledzić te najgorsze i raportować tylko informacje o nich.

Nie chodzi o wykrywanie i naprawianie wszystkich przesunięć układu, które występują u każdego użytkownika. Celem jest identyfikowanie przesunięć, które mają wpływ na największą liczbę użytkowników, a tym samym w największym stopniu przyczyniają się do wartości CLS strony na 75 percentylu.

Nie musisz też obliczać największego elementu źródłowego za każdym razem, gdy następuje przesunięcie. Wystarczy, że zrobisz to, gdy będziesz gotowy(-a) do wysłania wartości CLS do narzędzia analitycznego.

Poniższy kod pobiera listę wpisów layout-shift, które przyczyniły się do CLS, i zwraca największy element źródłowy z największego przesunięcia:

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

Gdy zidentyfikujesz największy element, który przyczynił się do największej zmiany, możesz przekazać tę informację do narzędzia analitycznego.

Element, który w przypadku danej strony ma największy wpływ na CLS, może się różnić w zależności od użytkownika. Jeśli jednak zbierzesz te elementy od wszystkich użytkowników, będziesz w stanie wygenerować listę przesuwających się elementów, które mają wpływ na największą liczbę użytkowników.

Po zidentyfikowaniu i usunięciu głównej przyczyny przesunięć tych elementów kod analityczny zacznie zgłaszać mniejsze przesunięcia jako „najgorsze” przesunięcia na stronach. W końcu wszystkie zgłoszone zmiany będą na tyle małe, że Twoje strony będą mieścić się w „dobrym” progu wynoszącym 0,1.

Inne metadane, które mogą być przydatne do rejestrowania wraz z elementem źródłowym największego przesunięcia:

  • Godzina największej zmiany
  • Ścieżka adresu URL w momencie największej zmiany (w przypadku witryn, które dynamicznie aktualizują adres URL, np. aplikacji jednostronicowych).

Największe wyrenderowanie treści (LCP)

Aby debugować LCP w warunkach rzeczywistych, musisz przede wszystkim wiedzieć, który element był największy (element kandydujący do LCP) podczas wczytywania danej strony.

Pamiętaj, że element kandydujący do LCP może się różnić w zależności od użytkownika, nawet w przypadku tej samej strony.

Dzieje się tak z kilku powodów:

  • Urządzenia użytkowników mają różne rozdzielczości ekranu, co powoduje różne układy stron, a tym samym różne elementy widoczne w obszarze widoku.
  • Użytkownicy nie zawsze wczytują strony przewinięte do samej góry. Często linki zawierają identyfikatory fragmentów lub nawet fragmenty tekstu, co oznacza, że strony mogą być wczytywane i wyświetlane w dowolnym miejscu na stronie.
  • Treści mogą być spersonalizowane pod kątem bieżącego użytkownika, więc element kandydujący do LCP może się znacznie różnić w zależności od użytkownika.

Oznacza to, że nie możesz zakładać, który element lub zestaw elementów będzie najczęstszym kandydatem do LCP na danej stronie. Musisz mierzyć go na podstawie zachowań rzeczywistych użytkowników.

Określanie elementu kandydującego do LCP

Aby określić element kandydujący do LCP w JavaScript, możesz użyć interfejsu Largest Contentful Paint API, czyli tego samego interfejsu API, którego używasz do określania wartości czasu LCP.

Obserwując wpisy largest-contentful-paint, możesz określić bieżący element kandydujący do LCP, sprawdzając właściwość element ostatniego wpisu:

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

Gdy poznasz element kandydujący do LCP, możesz wysłać go do narzędzia analitycznego wraz z wartością danych. Podobnie jak w przypadku CLS pomoże Ci to określić, które elementy są najważniejsze i warto je zoptymalizować w pierwszej kolejności.

Oprócz elementu kandydującego do LCP warto też mierzyć czasy poszczególnych części LCP, co może być przydatne w określaniu, jakie konkretne kroki optymalizacji są istotne w przypadku Twojej witryny.

Interakcja do kolejnego wyrenderowania (INP)

Najważniejsze informacje, które należy zebrać w przypadku INP, to:

  1. Z którym elementem przeprowadzono interakcję
  2. rodzaj interakcji,
  3. kiedy doszło do interakcji;

Główną przyczyną powolnych interakcji jest zablokowany wątek główny, co może się zdarzać podczas wczytywania JavaScriptu. Informacja o tym, czy większość powolnych interakcji występuje podczas wczytywania strony, pomaga określić, co należy zrobić, aby rozwiązać problem.

Wskaźnik INP uwzględnia pełne opóźnienie interakcji, w tym czas potrzebny na uruchomienie wszystkich zarejestrowanych detektorów zdarzeń, a także czas potrzebny na wyrenderowanie następnej klatki po uruchomieniu wszystkich detektorów zdarzeń. Oznacza to, że w przypadku INP bardzo przydatne jest wiedzieć, które elementy docelowe powodują wolne interakcje i jakiego rodzaju są te interakcje.

Poniższy kod rejestruje element docelowy i czas wpisu INP.

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

Pamiętaj, że ten kod nie pokazuje, jak określić, które wpisy event są wpisami INP, ponieważ ta logika jest bardziej złożona. W sekcji poniżej znajdziesz jednak informacje o tym, jak uzyskać te dane za pomocą biblioteki JavaScript web-vitals.

Korzystanie z biblioteki JavaScript web-vitals

W poprzednich sekcjach znajdziesz ogólne sugestie i przykłady kodu, które pomogą Ci rejestrować dane debugowania, aby uwzględniać je w danych przesyłanych do narzędzia analitycznego.

Od wersji 3 biblioteka JavaScript web-vitals zawiera wersję z atrybucją, która udostępnia wszystkie te informacje, a także kilka dodatkowych sygnałów.

Poniższy przykład kodu pokazuje, jak ustawić dodatkowy parametr zdarzenia (lub niestandardowy wymiar) zawierający ciąg debugowania, który pomaga zidentyfikować główną przyczynę problemów z wydajnością.

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

Ten kod jest specyficzny dla Google Analytics, ale ogólna idea powinna być też przydatna w przypadku innych narzędzi analitycznych.

Ten kod pokazuje też, jak raportować pojedynczy sygnał debugowania, ale warto mieć możliwość zbierania i raportowania wielu różnych sygnałów na potrzeby każdego rodzaju danych.

Aby na przykład debugować INP, możesz zbierać informacje o elemencie, z którym użytkownik wchodzi w interakcję, typie interakcji, czasie, stanie wczytywania, fazach interakcji i inne dane (np. dane o długich klatkach animacji).

web-vitals Atrybucja kompilacji udostępnia dodatkowe informacje o atrybucji, jak pokazano w tym przykładzie dotyczącym 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);

Pełną listę udostępnianych sygnałów debugowania znajdziesz w dokumentacji dotyczącej atrybucji wskaźników Web Vitals.

Raportowanie i wizualizowanie danych

Gdy zaczniesz zbierać informacje na potrzeby debugowania wraz z wartościami danych, następnym krokiem będzie agregowanie danych wszystkich użytkowników, aby zacząć szukać wzorców i trendów.

Jak już wspomnieliśmy, nie musisz rozwiązywać wszystkich problemów, z którymi spotykają się użytkownicy. Na początku warto zająć się tymi, które dotyczą największej liczby użytkowników i mają największy negatywny wpływ na wyniki Core Web Vitals.

W przypadku GA4 zapoznaj się z artykułem na temat wykonywania zapytań i wizualizacji danych za pomocą BigQuery.

Podsumowanie

Mamy nadzieję, że ten post pomógł Ci poznać konkretne sposoby wykorzystania obecnych interfejsów API wydajności i biblioteki web-vitals do uzyskiwania informacji na potrzeby debugowania, które pomogą Ci diagnozować wydajność na podstawie wizyt prawdziwych użytkowników w terenie. Ten przewodnik koncentruje się na podstawowych wskaźnikach internetowych, ale opisane w nim koncepcje mają zastosowanie również do debugowania dowolnych danych o wydajności, które można zmierzyć w JavaScript.

Jeśli jesteś dostawcą usług analitycznych i chcesz ulepszyć swoje produkty oraz dostarczać użytkownikom więcej informacji na potrzeby debugowania, rozważ zastosowanie niektórych opisanych tu technik, ale nie ograniczaj się tylko do przedstawionych tu pomysłów. Ten post ma zastosowanie do wszystkich narzędzi analitycznych, ale poszczególne narzędzia analityczne mogą (i powinny) rejestrować i raportować jeszcze więcej informacji na potrzeby debugowania.

Jeśli uważasz, że nie możesz debugować tych danych z powodu brakujących funkcji lub informacji w samych interfejsach API, wyślij opinię na adres web-vitals-feedback@googlegroups.com.