Dowiedz się, jak znaleźć w danych z terenu dotyczące Twojej witryny informacje o powolnych interakcjach, aby znaleźć możliwości poprawy czasu od interakcji do kolejnego wyrenderowania.
Dane z terenu to dane, które pokazują, jak prawdziwi użytkownicy korzystają z Twojej witryny. Ujawnia problemy, których nie można znaleźć na podstawie samych danych laboratoryjnych. W przypadku interakcji do kolejnego wyrenderowania (INP) dane z terenu są niezbędne do identyfikowania powolnych interakcji i dostarczają istotnych wskazówek, które pomagają je naprawić.
Z tego przewodnika dowiesz się, jak szybko ocenić INP witryny za pomocą danych z Raportu na temat użytkowania Chrome (CrUX), aby sprawdzić, czy witryna ma problemy z INP. Następnie dowiesz się, jak używać wersji atrybucyjnej biblioteki JavaScript web-vitals i nowych statystyk, które udostępnia interfejs Long Animation Frames API (LoAF), do zbierania i interpretowania danych z terenu dotyczących powolnych interakcji w Twojej witrynie.
Zacznij od CrUX, aby ocenić INP witryny
Jeśli nie zbierasz danych z witryny od użytkowników, CrUX może być dobrym punktem wyjścia. CrUX zbiera dane z pól od rzeczywistych użytkowników Chrome, którzy wyrazili zgodę na wysyłanie danych telemetrycznych.
Dane CrUX są dostępne w wielu różnych miejscach, w zależności od zakresu informacji, których szukasz. CrUX może dostarczać dane o INP i innych podstawowych wskaźnikach internetowych w przypadku:
- poszczególne strony i całe domeny za pomocą PageSpeed Insights;
- Rodzaje stron. Wiele witryn e-commerce ma na przykład typy stron „Strona z informacjami o produkcie” i „Strona z listą produktów”. Dane CrUX dotyczące unikalnych typów stron możesz uzyskać w Search Console.
Na początek możesz wpisać adres URL swojej witryny w PageSpeed Insights. Po wpisaniu adresu URL wyświetlą się dane z pola (jeśli są dostępne) dla wielu wskaźników, w tym INP. Możesz też użyć przełączników, aby sprawdzić wartości INP dla wymiarów na urządzeniach mobilnych i komputerach.

Te dane są przydatne, ponieważ informują, czy występuje problem. CrUX nie może jednak określić, co powoduje problemy. Dostępnych jest wiele rozwiązań do monitorowania użytkowników (RUM), które pomogą Ci zbierać własne dane z pól od użytkowników Twojej witryny, aby uzyskać odpowiedź na to pytanie. Jedną z opcji jest samodzielne zbieranie tych danych za pomocą biblioteki JavaScript web-vitals.
Zbieranie danych o polach za pomocą biblioteki JavaScript web-vitals
web-vitals
Biblioteka JavaScriptu to skrypt, który możesz wczytać w swojej witrynie, aby zbierać dane z pól od użytkowników witryny. Możesz go używać do rejestrowania wielu danych, w tym INP w przeglądarkach, które go obsługują.
Standardowa wersja biblioteki web-vitals może służyć do uzyskiwania podstawowych danych INP od użytkowników w terenie:
import {onINP} from 'web-vitals';
onINP(({name, value, rating}) => {
console.log(name); // 'INP'
console.log(value); // 512
console.log(rating); // 'poor'
});
Aby analizować dane z pól od użytkowników, musisz je gdzieś wysyłać:
import {onINP} from 'web-vitals';
onINP(({name, value, rating}) => {
// Prepare JSON to be sent for collection. Note that
// you can add anything else you'd want to collect here:
const body = JSON.stringify({name, value, rating});
// Use `sendBeacon` to send data to an analytics endpoint.
// For Google Analytics, see https://github.com/GoogleChrome/web-vitals#send-the-results-to-google-analytics.
navigator.sendBeacon('/analytics', body);
});
Same te dane nie mówią jednak nic więcej niż dane z raportu CrUX. W takich przypadkach przydaje się wersja biblioteki web-vitals do atrybucji.
Więcej możliwości dzięki wersji biblioteki web-vitals do atrybucji
Wersja atrybucji biblioteki web-vitals udostępnia dodatkowe dane, które możesz uzyskać od użytkowników w terenie, aby lepiej rozwiązywać problemy z interakcjami wpływającymi na INP Twojej witryny. Dostęp do tych danych można uzyskać za pomocą obiektu attribution
, który jest udostępniany w metodzie onINP()
biblioteki:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, rating, attribution}) => {
console.log(name); // 'INP'
console.log(value); // 56
console.log(rating); // 'good'
console.log(attribution); // Attribution data object
});

Oprócz samego INP strony atrybucja dostarcza wiele danych, które pomogą Ci zrozumieć przyczyny powolnych interakcji, w tym to, na której części interakcji należy się skupić. Może Ci pomóc w znalezieniu odpowiedzi na ważne pytania, takie jak:
- „Czy użytkownik wszedł w interakcję ze stroną podczas jej wczytywania?”
- „Czy moduły obsługi zdarzeń interakcji działały przez długi czas?”
- „Czy kod obsługi zdarzenia interakcji został opóźniony? Jeśli tak, co jeszcze działo się wtedy w głównym wątku?”.
- „Czy interakcja spowodowała dużo pracy związanej z renderowaniem, która opóźniła wyrenderowanie następnej klatki?”
W tabeli poniżej znajdziesz niektóre podstawowe dane o atrybucji, które możesz uzyskać z biblioteki i które pomogą Ci ustalić ogólne przyczyny powolnych interakcji w Twojej witrynie:
attribution klucz obiektu
|
Dane |
---|---|
interactionTarget
|
Selektor CSS wskazujący element, który wygenerował wartość INP strony, np. button#save .
|
interactionType
|
Rodzaj interakcji, np. kliknięcia, dotknięcia lub wpisywanie z klawiatury. |
inputDelay *
|
Opóźnienie wejściowe interakcji. |
processingDuration *
|
Czas od momentu, gdy pierwszy odbiornik zdarzeń zaczął działać w odpowiedzi na interakcję użytkownika, do momentu zakończenia przetwarzania wszystkich odbiorników zdarzeń. |
presentationDelay *
|
Opóźnienie prezentacji interakcji, które występuje od momentu zakończenia działania obsługi zdarzeń do momentu narysowania następnej klatki. |
longAnimationFrameEntries *
|
Wpisy z listy LoAF powiązane z interakcją. Więcej informacji znajdziesz w następnej sekcji. |
Od wersji 4 biblioteki web-vitals możesz uzyskać jeszcze bardziej szczegółowe informacje o problematycznych interakcjach dzięki danym, które udostępnia ona w podziale na fazy INP (opóźnienie wejścia, czas przetwarzania i opóźnienie wyświetlania) oraz interfejs Long Animation Frames API (LoAF).
Long Animation Frames API (LoAF)
Debugowanie interakcji za pomocą danych z pola jest trudnym zadaniem. Dzięki danym z LoAF można jednak uzyskać lepszy wgląd w przyczyny powolnych interakcji, ponieważ LoAF udostępnia wiele szczegółowych pomiarów czasu i innych danych, które możesz wykorzystać do określenia dokładnych przyczyn, a co ważniejsze, miejsca, w którym w kodzie witryny występuje problem.
Wersja biblioteki web-vitals do atrybucji udostępnia tablicę wpisów LoAF pod kluczem longAnimationFrameEntries
obiektu attribution
. W tabeli poniżej znajdziesz kilka kluczowych informacji, które możesz znaleźć w każdym wpisie LoAF:
Klucz obiektu wpisu LoAF | Dane |
---|---|
duration
|
Czas trwania długiej klatki animacji do momentu zakończenia układu, ale z wyłączeniem malowania i komponowania. |
blockingDuration
|
Łączny czas w ramce, w którym przeglądarka nie mogła szybko zareagować z powodu długich zadań. Ten czas blokowania może obejmować długie zadania uruchamiające JavaScript, a także wszelkie kolejne długie zadania renderowania w ramce. |
firstUIEventTimestamp
|
Sygnatura czasowa zdarzenia, które zostało umieszczone w kolejce w trakcie klatki. Przydatne do określania początku opóźnienia wejściowego interakcji. |
startTime
|
Sygnatura czasowa rozpoczęcia klatki. |
renderStart
|
Czas rozpoczęcia renderowania klatki. Obejmuje to wszystkie wywołania zwrotne requestAnimationFrame (i w odpowiednich przypadkach wywołania zwrotne ResizeObserver ), ale potencjalnie przed rozpoczęciem prac nad stylem lub układem.
|
styleAndLayoutStart
|
Gdy w ramce występuje praca związana ze stylem lub układem. Może być przydatne przy określaniu długości pracy nad stylem lub układem, gdy uwzględniasz inne dostępne sygnatury czasowe. |
scripts
|
Tablica elementów zawierających informacje o atrybucji skryptu, które mają wpływ na INP strony. |

blockingDuration
).
Wszystkie te informacje mogą wiele powiedzieć o tym, co powoduje spowolnienie interakcji, ale szczególnie interesująca powinna być tablica scripts
, którą zawierają wpisy LoAF:
Klucz obiektu atrybucji skryptu | Dane |
---|---|
invoker
|
Wywołujący. Może się to różnić w zależności od typu wywołującego opisanego w następnym wierszu. Przykładami wywołań mogą być wartości takie jak 'IMG#id.onload' , 'Window.requestAnimationFrame' lub 'Response.json.then' . |
invokerType
|
Typ wywołującego. Może to być 'user-callback' , 'event-listener' , 'resolve-promise' , 'reject-promise' , 'classic-script' lub 'module-script' .
|
sourceURL
|
Adres URL skryptu, z którego pochodzi długa klatka animacji. |
sourceCharPosition
|
Pozycja znaku w skrypcie oznaczonym jako sourceURL .
|
sourceFunctionName
|
Nazwa funkcji w zidentyfikowanym skrypcie. |
Każdy wpis w tej tablicy zawiera dane widoczne w tej tabeli, które dostarczają informacji o skrypcie odpowiedzialnym za powolną interakcję i o tym, w jaki sposób do niej doszło.
Mierzenie i identyfikowanie typowych przyczyn powolnych interakcji
Aby dać Ci wyobrażenie o tym, jak możesz wykorzystać te informacje, w tym przewodniku pokażemy, jak za pomocą danych LoAF wyświetlanych w web-vitals
bibliotece określić niektóre przyczyny powolnych interakcji.
Długi czas przetwarzania
Czas przetwarzania interakcji to czas, jaki zajmuje wykonanie zarejestrowanych wywołań zwrotnych modułu obsługi zdarzeń interakcji oraz wszelkich innych czynności, które mogą wystąpić między nimi. Długie czasy przetwarzania są wykrywane przez bibliotekę web-vitals:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {processingDuration} = attribution; // 512.5
});
Możesz sądzić, że główną przyczyną powolnej interakcji jest zbyt długi czas działania kodu obsługi zdarzeń, ale nie zawsze tak jest. Gdy potwierdzisz, że to jest problem, możesz dokładniej go zbadać, korzystając z danych LoAF:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {processingDuration} = attribution; // 512.5
// Get the longest script from LoAF covering `processingDuration`:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
if (script) {
// Get attribution for the long-running event handler:
const {invokerType} = script; // 'event-listener'
const {invoker} = script; // 'BUTTON#update.onclick'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Jak widać w poprzednim fragmencie kodu, możesz pracować z danymi LoAF, aby znaleźć dokładną przyczynę interakcji o wysokich wartościach czasu przetwarzania, w tym:
- Element i zarejestrowany detektor zdarzeń.
- Plik skryptu i pozycja znaku w nim, które zawierają kod długotrwałego modułu obsługi zdarzeń.
- Nazwa funkcji.
Ten typ danych jest nieoceniony. Nie musisz już samodzielnie sprawdzać, która interakcja lub który z jej modułów obsługi zdarzeń odpowiada za wysokie wartości czasu przetwarzania. Ponadto skrypty innych firm często rejestrują własne procedury obsługi zdarzeń, więc możesz sprawdzić, czy to Twój kod był odpowiedzialny za zdarzenie. W przypadku kodu, nad którym masz kontrolę, warto przyjrzeć się optymalizacji długich zadań.
Długie opóźnienia wejściowe
Długotrwałe procedury obsługi zdarzeń są powszechne, ale warto wziąć pod uwagę inne elementy interakcji. Jedna część występuje przed czasem przetwarzania i jest nazywana opóźnieniem wejściowym. Jest to czas od momentu, w którym użytkownik rozpoczyna interakcję, do momentu, w którym zaczynają działać wywołania zwrotne obsługi zdarzeń. Dzieje się to, gdy wątek główny przetwarza już inne zadanie. Wersja atrybucji biblioteki web-vitals może podać długość opóźnienia danych wejściowych w przypadku interakcji:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
});
Jeśli zauważysz, że niektóre interakcje mają duże opóźnienia, musisz ustalić, co działo się na stronie w momencie interakcji, która spowodowała długie opóźnienie. Często sprowadza się to do tego, czy interakcja nastąpiła podczas ładowania strony, czy po nim.
Czy wystąpił podczas wczytywania strony?
Główny wątek jest zwykle najbardziej obciążony podczas wczytywania strony. W tym czasie kolejkowane i przetwarzane są różnego rodzaju zadania. Jeśli użytkownik spróbuje wejść w interakcję ze stroną, gdy to wszystko się dzieje, może to opóźnić interakcję. Strony, które wczytują dużo kodu JavaScript, mogą rozpocząć kompilowanie i ocenianie skryptów, a także wykonywanie funkcji, które przygotowują stronę do interakcji z użytkownikiem. Może to przeszkadzać użytkownikowi, jeśli w trakcie wykonywania tych działań wejdzie on w interakcję ze stroną. Możesz sprawdzić, czy tak jest w przypadku użytkowników Twojej witryny:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
// Get the longest script from the first LoAF entry:
const loaf = attribution.longAnimationFrameEntries[0];
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
if (script) {
// Invoker types can describe if script eval blocked the main thread:
const {invokerType} = script; // 'classic-script' | 'module-script'
const {sourceLocation} = script; // 'https://example.com/app.js'
}
});
Jeśli rejestrujesz te dane w terenie i widzisz duże opóźnienia we wprowadzaniu danych oraz typy wywołujących 'classic-script'
lub 'module-script'
, można stwierdzić, że skrypty w Twojej witrynie długo się wykonują i blokują wątek główny na tyle długo, że opóźniają interakcje. Możesz skrócić ten czas blokowania, dzieląc skrypty na mniejsze pakiety, odraczając wczytywanie początkowo nieużywanego kodu na późniejszy moment i sprawdzając witrynę pod kątem nieużywanego kodu, który możesz całkowicie usunąć.
Czy po wczytaniu strony?
Opóźnienia we wprowadzaniu danych często występują podczas ładowania strony, ale mogą też pojawić się po jej załadowaniu z zupełnie innego powodu. Częstymi przyczynami opóźnień w reagowaniu na dane wejściowe po wczytaniu strony mogą być kod, który jest uruchamiany okresowo z powodu wcześniejszego wywołania setInterval
, lub nawet wywołania zwrotne zdarzeń, które zostały umieszczone w kolejce do uruchomienia wcześniej i są nadal przetwarzane.
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
// Get the longest script from the first LoAF entry:
const loaf = attribution.longAnimationFrameEntries[0];
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
if (script) {
const {invokerType} = script; // 'user-callback'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Podobnie jak w przypadku rozwiązywania problemów z wysokimi wartościami czasu przetwarzania, duże opóźnienia wejściowe spowodowane wspomnianymi wcześniej przyczynami dostarczą Ci szczegółowych danych o atrybucji skryptu. Różnica polega jednak na tym, że typ wywołującego zmieni się w zależności od charakteru pracy, która opóźniła interakcję:
'user-callback'
oznacza, że zadanie blokowania pochodziło zsetInterval
,setTimeout
lub nawetrequestAnimationFrame
.'event-listener'
oznacza, że zadanie blokujące pochodziło z wcześniejszego wejścia, które zostało umieszczone w kolejce i jest nadal przetwarzane.'resolve-promise'
i'reject-promise'
oznaczają, że zadanie blokujące pochodziło z pracy asynchronicznej, która została rozpoczęta wcześniej i zakończona lub odrzucona w momencie, gdy użytkownik próbował wejść w interakcję ze stroną, co opóźniło tę interakcję.
W każdym przypadku dane atrybucji skryptu pomogą Ci określić, od czego zacząć poszukiwania i czy opóźnienie wejściowe było spowodowane Twoim kodem, czy skryptem innej firmy.
Długie opóźnienia prezentacji
Opóźnienia prezentacji to ostatni etap interakcji. Rozpoczynają się one po zakończeniu działania procedur obsługi zdarzeń interakcji i trwają do momentu narysowania następnej klatki. Występują one, gdy praca w obsłudze zdarzeń spowodowana interakcją zmienia stan wizualny interfejsu. Podobnie jak w przypadku czasu przetwarzania i opóźnień wejściowych, biblioteka web-vitals może podać czas opóźnienia prezentacji w przypadku interakcji:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 113.32307691
});
Jeśli rejestrujesz te dane i widzisz duże opóźnienia w wyświetlaniu interakcji, które mają wpływ na INP Twojej witryny, przyczyny mogą być różne, ale oto kilka, na które warto zwrócić uwagę.
Kosztowna praca nad stylem i układem
Długie opóźnienia w prezentacji mogą być spowodowane kosztownym ponownym obliczaniem stylu i układu, które wynikają z wielu przyczyn, w tym ze złożonych selektorów CSS i dużych rozmiarów DOM. Możesz zmierzyć czas trwania tej pracy za pomocą danych LoAF udostępnianych w bibliotece web-vitals:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 113.32307691
// Get the longest script from the last LoAF entry:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
// Get necessary timings:
const {startTime} = loaf; // 2120.5
const {duration} = loaf; // 1002
// Figure out the ending timestamp of the frame (approximate):
const endTime = startTime + duration; // 3122.5
// Get the start timestamp of the frame's style/layout work:
const {styleAndLayoutStart} = loaf; // 3011.17692309
// Calculate the total style/layout duration:
const styleLayoutDuration = endTime - styleAndLayoutStart; // 111.32307691
if (script) {
// Get attribution for the event handler that triggered
// the long-running style and layout operation:
const {invokerType} = script; // 'event-listener'
const {invoker} = script; // 'BUTTON#update.onclick'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
LoAF nie podaje czasu trwania pracy nad stylem i układem w przypadku klatki, ale informuje, kiedy się ona rozpoczęła. Na podstawie tego znacznika czasu możesz użyć innych danych z LoAF, aby obliczyć dokładny czas trwania pracy. Wystarczy, że określisz czas zakończenia klatki i odejmiesz od niego znacznik czasu rozpoczęcia pracy nad stylem i układem.
Długotrwałe wywołania zwrotne requestAnimationFrame
Jedną z potencjalnych przyczyn długich opóźnień w wyświetlaniu jest nadmierna praca wykonywana w wywołaniu zwrotnym requestAnimationFrame
. Zawartość tego wywołania zwrotnego jest wykonywana po zakończeniu działania procedur obsługi zdarzeń, ale tuż przed ponownym obliczeniem stylu i pracą związaną z układem.
Jeśli wykonywane w nich działania są złożone, wywołania zwrotne mogą trwać dość długo. Jeśli podejrzewasz, że wysokie wartości opóźnienia prezentacji są spowodowane pracą, którą wykonujesz w requestAnimationFrame
, możesz użyć danych LoAF udostępnianych przez bibliotekę web-vitals, aby zidentyfikować te scenariusze:
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 543.1999999880791
// Get the longest script from the last LoAF entry:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
// Get the render start time and when style and layout began:
const {renderStart} = loaf; // 2489
const {styleAndLayoutStart} = loaf; // 2989.5999999940395
// Calculate the `requestAnimationFrame` callback's duration:
const rafDuration = styleAndLayoutStart - renderStart; // 500.59999999403954
if (script) {
// Get attribution for the event handler that triggered
// the long-running requestAnimationFrame callback:
const {invokerType} = script; // 'user-callback'
const {invoker} = script; // 'FrameRequestCallback'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Jeśli zauważysz, że znaczna część czasu opóźnienia prezentacji jest poświęcana na requestAnimationFrame
wywołanie zwrotne, upewnij się, że praca wykonywana w ramach tych wywołań zwrotnych ogranicza się do działań, które powodują rzeczywistą aktualizację interfejsu. Wszelkie inne działania, które nie wpływają na DOM ani nie aktualizują stylów, niepotrzebnie opóźnią rysowanie następnej klatki, więc zachowaj ostrożność.
Podsumowanie
Dane z terenu to najlepsze źródło informacji, z którego możesz korzystać, aby dowiedzieć się, które interakcje są problematyczne dla rzeczywistych użytkowników. Korzystając z narzędzi do zbierania danych w terenie, takich jak biblioteka JavaScript web-vitals (lub dostawca RUM), możesz mieć większą pewność, które interakcje są najbardziej problematyczne. Następnie możesz odtworzyć problematyczne interakcje w laboratorium i je naprawić.
Baner powitalny z Unsplash, autor: Federico Respini.