Interfejs API Long Animation Frames

Interfejs Long Animation Frames API (LoAF, wymawiane jako Lo-Af) to aktualizacja interfejsu Long Tasks API, która ma na celu ułatwienie zrozumienia powolnych aktualizacji interfejsu użytkownika. Może to być przydatne do identyfikowania klatek animacji, które są wolne i mogą wpływać na podstawowy wskaźnik internetowy Interakcja do kolejnego wyrenderowania (INP), który mierzy responsywność, lub innych problemów z płynnością interfejsu, które wpływają na płynność.

Stan interfejsu API

Obsługa przeglądarek

  • Chrome: 123.
  • Edge: 123.
  • Firefox: funkcja nieobsługiwana.
  • Safari: nieobsługiwane.

Źródło

Po testowaniu origin w Chrome 116–122 interfejs LoAF API został wprowadzony w Chrome 123.

Wprowadzenie: interfejs Long Tasks API

Obsługa przeglądarek

  • Chrome: 58.
  • Edge: 79.
  • Firefox: nieobsługiwane.
  • Safari: nieobsługiwane.

Źródło

Interfejs API Long Animation Frames jest alternatywą dla interfejsu Long Tasks API, który jest dostępny w Chrome od jakiegoś czasu (od wersji 58). Jak sama nazwa wskazuje, interfejs Long Task API umożliwia monitorowanie długich zadań, czyli takich, które zajmują wątek główny przez co najmniej 50 ms. Długie zadania można monitorować za pomocą interfejsu PerformanceLongTaskTiming i PeformanceObserver:

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

observer.observe({ type: 'longtask', buffered: true });

Długie zadania mogą powodować problemy z czasem reakcji. Jeśli użytkownik próbuje wchodzić w interakcję ze stroną, np. kliknąć przycisk lub otworzyć menu, ale główny wątek już wykonuje długie zadanie, interakcja użytkownika jest opóźniona, ponieważ czeka na zakończenie tego zadania.

Aby poprawić czas reagowania, często zaleca się podzielenie długich zadań. Jeśli każde długie zadanie zostanie podzielone na kilka mniejszych zadań, może to umożliwić wykonywanie ważniejszych zadań między nimi, co pozwoli uniknąć znacznych opóźnień w reagowaniu na interakcje.

Dlatego, gdy chcesz poprawić szybkość reakcji, pierwszym krokiem jest często uruchomienie śledzenia wydajności i sprawdzenie długich zadań. Można to zrobić za pomocą narzędzia kontrolnego opartego na laboratorium, takiego jak Lighthouse (z aplikacją Unikaj długich zadań w wątku głównym) lub przeglądanie długich zadań w Narzędziach deweloperskich w Chrome.

Testowanie w laboratorium często nie jest dobrym punktem wyjścia do identyfikowania problemów z responsywnością, ponieważ te narzędzia mogą nie uwzględniać interakcji – a jeśli tak się dzieje, to tylko niewielkiej podgrupy możliwych interakcji. Najlepiej jest mierzyć przyczyny powołujące do wydłużenia się interakcji w polu.

Wady interfejsu Long Tasks API

Pomiar długich zadań w polu za pomocą narzędzia Performance Observer jest tylko w pewnym stopniu przydatny. W rzeczywistości nie zawiera ono zbyt wielu informacji, poza tym, że miało miejsce długie zadanie i ile ono trwało.

Narzędzia do monitorowania rzeczywistych użytkowników (RUM) często wykorzystują te dane do analizy trendów dotyczących liczby lub czasu trwania długich zadań oraz do określania, na których stronach występują. Jednak bez szczegółowych informacji o przyczynach długiego czasu wykonywania zadań ich przydatność jest ograniczona. Interfejs Long Tasks API ma tylko podstawowy model atrybucji, który w najlepszym przypadku podaje tylko kontener, w którym wystąpiło długie zadanie (dokument najwyższego poziomu lub <iframe>), ale nie skryptu ani funkcji, które je wywołały. Przykładowy wpis:

{
  "name": "unknown",
  "entryType": "longtask",
  "startTime": 31.799999997019768,
  "duration": 136,
  "attribution": [
    {
      "name": "unknown",
      "entryType": "taskattribution",
      "startTime": 0,
      "duration": 0,
      "containerType": "window",
      "containerSrc": "",
      "containerId": "",
      "containerName": ""
    }
  ]
}

Interfejs API Long Tasks również nie jest pełnym widokiem, ponieważ może pomijać niektóre ważne zadania. Niektóre aktualizacje, np. renderowanie, odbywają się w ramach osobnych zadań, które najlepiej uwzględnić razem z poprzednim wykonaniem, które spowodowało tę aktualizację, aby dokładnie mierzyć „całkowity wysiłek” związany z tą interakcją. Więcej informacji o ograniczeniach polegania na zadaniach znajdziesz w sekcji wyjaśnienia „Gdzie są długie zadania”.

Ostatni problem polega na tym, że pomiar długich zadań uwzględnia w raportach tylko poszczególne zadania, których czas trwania przekracza 50 milisekund. Ramka animacji może składać się z kilku zadań krótszych niż ten limit 50 milisekund, ale łącznie blokujemy w przeglądarce możliwość renderowania.

Interfejs API Long Animation Frames

Obsługa przeglądarek

  • Chrome: 123.
  • Edge: 123.
  • Firefox: nieobsługiwane.
  • Safari: nieobsługiwane.

Źródło

Long Animation Frames API (LoAF) to nowy interfejs API, który ma na celu wyeliminowanie niektórych niedoskonałości interfejsu Long Tasks API, aby umożliwić deweloperom uzyskiwanie bardziej przydatnych informacji, które pomogą im rozwiązać problemy z szybkością działania i poprawią INP, a także dostarczą informacji o płynności.

Dobra responsywność oznacza, że strona szybko reaguje na interakcje z użytkownikiem. Polega to na umieszczaniu potrzebnych aktualizacji w odpowiednim czasie oraz zapobieganiu ich blokowaniu. W przypadku INP zalecamy, aby czas reakcji nie przekraczał 200 milisekund, ale w przypadku innych aktualizacji (np. animacji) nawet 200 milisekund może być zbyt długim czasem.

Interfejs API Long Animation Frames to alternatywne podejście do pomiaru blokowania pracy. Jak sama nazwa wskazuje, interfejs Long Animation Frames API mierzy nie poszczególne zadania, ale długie klatki animacji. Długi element animacji to taki, którego aktualizacja renderowania jest opóźniona o więcej niż 50 ms (wartość ta jest taka sama jak próg dla interfejsu Long Tasks API).

Czas trwania długich klatek animacji jest mierzony od początku zadań, które wymagają renderowania. Jeśli pierwsze zadanie w potencjalnie długiej klatce animacji nie wymaga wyrenderowania, długa klatka animacji kończy się po zakończeniu zadania nierenderowanego, a następnym zadaniem jest rozpoczęcie nowej potencjalnie długiej klatki animacji. Takie nierenderowane długie klatki animacji są nadal uwzględniane w Long Animation Frames API, jeśli ich długość przekracza 50 ms (a czas renderStart wynosi 0), aby umożliwić pomiar potencjalnie blokującej pracy.

Długie klatki animacji można obserwować podobnie jak długie zadania z wartością PerformanceObserver, ale z uwzględnieniem typu long-animation-frame:

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

observer.observe({ type: 'long-animation-frame', buffered: true });

Poprzednie długie klatki animacji można też wyszukiwać na osi czasu skuteczności w ten sposób:

const loafs = performance.getEntriesByType('long-animation-frame');

Jest jednak wartość maxBufferSize dla wpisów dotyczących skuteczności, po której nowsze wpisy są pomijane, dlatego zalecamy podejście PerformanceObserver. Rozmiar bufora long-animation-frame jest ustawiony na 200, tak samo jak w przypadku long-tasks.

Zalety analizowania ramek zamiast zadań

Główną zaletą spojrzenia na ten model z perspektywy klatki, a nie z perspektywy zadań, jest to, że długa animacja może się składać z dowolnej liczby działań, które łącznie spowodowały wyświetlenie długiej klatki animacji. Rozwiązaniem jest ostatni wspomniany wcześniej problem, w którym suma wielu mniejszych zadań blokujących renderowanie przed ramką animacji może nie być wyświetlana przez interfejs API Long Tasks.

Kolejną zaletą tego alternatywnego widoku długich zadań jest możliwość wyświetlania podziału czasu w całym interwale. W odróżnieniu od interfejsu Long Tasks API, który zawiera tylko startTimeduration, interfejs Long Tasks for Frames zawiera znacznie bardziej szczegółowy podział na różne części czasu trwania ramki.

Sygnatury czasowe i czasy trwania klatek

  • startTime: czas rozpoczęcia długiej klatki animacji w stosunku do czasu rozpoczęcia nawigacji.
  • duration: czas trwania długiej klatki animacji (nie uwzględnia czasu prezentacji).
  • renderStart: czas rozpoczęcia cyklu renderowania, który obejmuje wywołania requestAnimationFrame, obliczenia stylu i układu, wywołania obserwatora zmiany rozmiaru i wywołania obserwatora przecięcia.
  • styleAndLayoutStart: początek okresu spędzonego na obliczaniu stylu i układu.
  • firstUIEventTimestamp: czas pierwszego zdarzenia interfejsu (myszki/klawiatury itd.), które ma być obsługiwane podczas wyświetlania tej klatki.
  • blockingDuration: łączny czas trwania w milisekundach, przez który ramka animacji blokuje przetwarzanie danych wejściowych lub innych zadań o wysokim priorytecie.

wyjaśnienie terminu blockingDuration,

Długa klatka animacji może składać się z wielu zadań. Wartość blockingDuration to suma czasów trwania zadań dłuższych niż 50 milisekund (wraz z ostatecznym czasem renderowania w najdłuższym zadaniu).

Jeśli na przykład długa klatka animacji składała się z 2 zadań o długości 55 milisekund i 65 milisekund, po których następuje renderowanie trwające 20 milisekund, pole duration będzie miało około 140 milisekund z parametrem blockingDuration o wartości (55 – 50) + (65 + 20 – 50) = 40 milisekund. W ciągu 40 milisekund z 140 milisekund trwania tego klatki animacji uznaliśmy, że blokuje ona przetwarzanie danych wejściowych.

Czy chcesz sprawdzić duration czy blockingDuration

W przypadku typowych wyświetlaczy o częstotliwości 60 Hz przeglądarka próbuje wyświetlać klatkę z co najmniej 16, 66 milisekundy (aby zapewnić płynne aktualizacje) lub po wykonaniu zadania o wysokim priorytecie, takiego jak obsługa danych wejściowych (aby zapewnić elastyczność aktualizacji). Jeśli jednak nie ma danych wejściowych ani innych zadań o wysokim priorytecie, ale jest kolejka innych zadań, przeglądarka zwykle kontynuuje bieżącą ramkę przez ponad 16,66 ms niezależnie od tego, jak dobrze są w niej rozmieszczone zadania. Oznacza to, że przeglądarka zawsze będzie starała się nadawać priorytety danym wejściowym, ale może zdecydować się na przetworzenie kolejki zadań zamiast aktualizacji. Wynika to z tego, że renderowanie jest kosztownym procesem, więc przetworzenie połączonego zadania renderowania dla wielu zadań zwykle prowadzi do ogólnego zmniejszenia pracy.

Dlatego długie klatki animacji z niskim lub zerowym blockingDuration powinny nadal reagować na dane wejściowe. Zmniejszenie lub wyeliminowanie blockingDuration przez podzielenie długich zadań jest więc kluczem do poprawy szybkości reakcji mierzonej za pomocą INP.

Jednak wiele długich klatek animacji – niezależnie od wartości blockingDuration oznacza, że aktualizacje interfejsu są opóźnione, przez co nadal mogą wpływać na płynność działania interfejsu użytkownika podczas przewijania lub animacji, nawet jeśli nie stanowią one większego problemu z czasem reakcji zgodnie z pomiarem INP. Aby zrozumieć problemy w tym obszarze, przyjrzyj się duration. Pamiętaj jednak, że ich optymalizacja może być trudniejsza do rozwiązania, bo nie da się tego rozwiązać przez podział pracy. Zamiast tego trzeba je ograniczyć.

Czasy wyświetlania klatek

Wspomniane wcześniej sygnatury czasowe umożliwiają podzielenie długiej klatki animacji na etapy:

Czas Obliczenie
Czas rozpoczęcia startTime
Czas zakończenia startTime + duration
Czas pracy renderStart ? renderStart - startTime : duration
Czas renderowania renderStart ? (startTime + duration) - renderStart: 0
Renderowanie: czas przed układem styleAndLayoutStart ? styleAndLayoutStart - renderStart : 0
Renderowanie: czas trwania stylizacji i układu styleAndLayoutStart ? (startTime + duration) - styleAndLayoutStart : 0

Lepsza atrybucja skryptu

Typ wpisu long-animation-frame zawiera lepsze dane atrybucji każdego skryptu, który przyczynił się do utworzenia długiego kadru animacji (w przypadku skryptów dłuższych niż 5 ms).

Podobnie jak w przypadku interfejsu Long Tasks API, dane te będą udostępniane w tablicy pozycji atrybucji, z których każda zawiera:

  • Zarówno name, jak i EntryType zwrócą wartość script.
  • znaczący parametr invoker, który wskazuje, jak wywołano skrypt (np. 'IMG#id.onload', 'Window.requestAnimationFrame' lub 'Response.json.then');
  • invokerType punktu wejścia skryptu:
    • user-callback: znane wywołanie zwrotne zarejestrowane przez interfejs API platformy internetowej (np. setTimeout, requestAnimationFrame).
    • event-listener: listener (nasłuchujący) zdarzenia platformy (np. click, load, keyup).
    • resolve-promise: obsługa platformy (na przykład fetch(). Pamiętaj, że w przypadku obietnic wszystkie moduły obsługi tych samych obietnic są wymieszane w jednym „skrypcie”)..
    • reject-promise: tak jak w resolve-promise, ale z odrzuceniem.
    • classic-script: ocena skryptu (np. <script> lub import())
    • module-script: taka sama jak classic-script, ale w przypadku skryptów modułu.
  • Osobne dane o czasie działania skryptu:
    • startTime: czas wywołania funkcji wpisu.
    • duration: czas od startTime do zakończenia przetwarzania kolejnej kolejki mikrozadań.
    • executionStart: czas po kompilacji.
    • forcedStyleAndLayoutDuration: łączny czas poświęcony na przetworzenie wymuszonej składni i stylu w ramach tej funkcji (patrz thrashing).
    • pauseDuration: łączny czas spędzony na „wstrzymywaniu” operacji synchronicznych (alert, synchroniczne żądania XHR).
  • Szczegóły źródła skryptu:
    • sourceURL: nazwa zasobu skryptu (jeśli jest dostępna) lub pusta wartość, jeśli nie znaleziono zasobu.
    • sourceFunctionName: nazwa funkcji skryptu, jeśli jest dostępna (lub pusta, jeśli nie została znaleziona).
    • sourceCharPosition: pozycja znaku skryptu, jeśli jest dostępna (lub -1, jeśli nie można jej znaleźć).
  • windowAttribution: kontener (dokument najwyższego poziomu lub <iframe>), w którym wystąpiła długa klatka animacji.
  • window: odwołanie do okna o tym samym pochodzeniu.

W przypadku, gdy są dostępne, wpisy źródłowe pozwalają deweloperom dokładnie określić, jak został wywołany każdy skrypt w ramach długiej animacji, aż do pozycji znaku w skrypcie wywołującym. Dzięki temu możesz określić dokładną lokalizację w zasobie JavaScriptu, która spowodowała długi kadr animacji.

Przykład wpisu dotyczącego skuteczności long-animation-frame

Przykład pełnego wpisu oceny long-animation-frame zawierającego 1 skrypt:

{
  "blockingDuration": 0,
  "duration": 60,
  "entryType": "long-animation-frame",
  "firstUIEventTimestamp": 11801.099999999627,
  "name": "long-animation-frame",
  "renderStart": 11858.800000000745,
  "scripts": [
    {
      "duration": 45,
      "entryType": "script",
      "executionStart": 11803.199999999255,
      "forcedStyleAndLayoutDuration": 0,
      "invoker": "DOMWindow.onclick",
      "invokerType": "event-listener",
      "name": "script",
      "pauseDuration": 0,
      "sourceURL": "https://web.dev/js/index-ffde4443.js",
      "sourceFunctionName": "myClickHandler",
      "sourceCharPosition": 17796,
      "startTime": 11803.199999999255,
      "window": [Window object],
      "windowAttribution": "self"
    }
  ],
  "startTime": 11802.400000000373,
  "styleAndLayoutStart": 11858.800000000745
}

Jak widać, daje to niespotykaną ilość danych, które umożliwiają ustalenie przyczyny opóźnień w renderowaniu.

Korzystanie z interfejsu Long Animation Frames API w praktyce

Narzędzia takie jak Narzędzia deweloperskie w Chrome i Lighthouse, choć przydatne do wykrywania i odtwarzania problemów, są narzędziami laboratoryjnymi, które mogą pomijać ważne aspekty wrażeń użytkownika, które są dostępne tylko w danych z pola.

Interfejs Long Animation Frames API jest przeznaczony do użycia w terenie do zbierania ważnych danych kontekstowych dotyczących interakcji użytkowników, których interfejs Long Task API nie mógł. Pomoże Ci to wykryć i odtworzyć problemy z interaktywnością, które w innym przypadku mogłyby pozostać niezauważone.

Obsługa interfejsu API wykrywania ramek długich animacji

Aby sprawdzić, czy interfejs API jest obsługiwany, możesz użyć tego kodu:

if (PerformanceObserver.supportedEntryTypes.includes('long-animation-frame')) {
  // Monitor LoAFs
}

Najbardziej oczywistym zastosowaniem interfejsu API Long Animation Frames jest diagnostyka i rozwiązywanie problemów z czasem od interakcji do następnego wyświetlenia (INP). Był to jeden z głównych powodów, dla których zespół Chrome opracował ten interfejs API. Dobra wartość INP to czas odpowiedzi na wszystkie interakcje w ciągu 200 milisekund od momentu wyrenderowania klatki. Ponieważ interfejs Long Animation Frames API mierzy wszystkie klatki, których długość trwa co najmniej 50 ms, większość problematycznych wartości INP powinna uwzględniać dane LoAF, aby ułatwić diagnozowanie tych interakcji.

„LoAF z interfejsem INP” to LoAF, który obejmuje interakcję INP, jak pokazano na diagramie poniżej:

Przykłady długich klatek animacji na stronie z wyróżnionym przyciskiem INP LoAF.
Strona może mieć wiele punktów wyjściowych, z których jeden jest powiązany z interakcją z interfejsem użytkownika.

W niektórych przypadkach zdarzenie INP może obejmować 2 LoAF – zwykle wtedy, gdy interakcja ma miejsce po rozpoczęciu renderowania części poprzedniej klatki przez klatkę, przez co moduł obsługi zdarzeń jest przetwarzany w następnej klatce:

Przykłady długich klatek animacji na stronie z wyróżnionym INP LoAF
Strona może mieć wiele LoAF, z których jeden jest powiązany z interakcją INP.

W rzadkich przypadkach może nawet obejmować więcej niż 2 LoAF.

Rejestrowanie danych LoAF związanych z interakcją z użyciem INP pozwala uzyskać więcej informacji o tej interakcji, co ułatwia jej diagnostykę. Jest to szczególnie przydatne, gdy chcesz poznać opóźnienie wprowadzania danych: możesz zobaczyć, jakie inne skrypty były wykonywane w danym ujęciu.

Może to być też przydatne, aby zrozumieć niewyjaśnione czasy przetwarzaniaopóźnienia wyświetlania, jeśli Twoje metody obsługi zdarzeń nie odtwarzają wartości, które są widoczne w przypadku innych skryptów, które mogą być uruchamiane dla użytkowników, ale nie są uwzględniane w Twoich testach.

Nie ma bezpośredniego interfejsu API do łączenia wpisu INP z powiązanymi wpisami LoAF, ale można to zrobić w kodzie, porównując czasy rozpoczęcia i zakończenia każdego z nich (patrz przykładowy skrypt WhyNp). Biblioteka web-vitals obejmuje wszystkie nakładające się punkty styku w usłudze longAnimationFramesEntries w interfejsie przypisywania INP w wersji 4.

Po połączeniu wpisów lub wpisów LoAF możesz dodawać informacje za pomocą atrybucji INP. Obiekt scripts zawiera jedne z najcenniejszych informacji, ponieważ może pokazywać, co jeszcze było wykonywane w tych ramach. Przesyłanie tych danych do usługi analitycznej pozwoli Ci lepiej zrozumieć, dlaczego interakcje były powolne.

Raportowanie LoAF w przypadku interakcji INP to dobry sposób na znalezienie najbardziej palących problemów z interaktywnością na stronie. Każdy użytkownik może inaczej wchodzić w interakcję ze stroną, a przy wystarczającej ilości danych o przypisaniu INP w tych danych może się pojawić pewna liczba potencjalnych problemów. Pozwala to na sortowanie skryptów według liczby, aby sprawdzić, które skrypty są powiązane z powolnym INP.

Przesyłanie do punktu końcowego analityki więcej danych o długich animacjach

Jednym z minusów analizowania tylko raportów o nieprawidłowościach w usłudze INP jest to, że możesz przeoczyć inne potencjalne obszary do ulepszenia, które mogą spowodować przyszłe problemy z INP. Może to wywołać uczucie ścigania własnego ogona, gdy naprawisz problem z czasem bezczynności, oczekując znacznej poprawy, a następna najdłuższa interakcja jest tylko nieznacznie lepsza, więc czas bezczynności nie ulega znacznemu skróceniu.

Zamiast analizować tylko LoAF w przypadku INP, warto wziąć pod uwagę wszystkie LoAF w całym okresie istnienia strony:

Strona z wiele LoAF, z których niektóre występują podczas interakcji, nawet jeśli nie jest to interakcja INP.
Sprawdzenie wszystkich LoAF może pomóc w identyfikacji przyszłych problemów z wartością INP.

Każdy wpis LoAF zawiera jednak znaczną ilość danych, więc prawdopodobnie zechcesz ograniczyć analizę tylko do niektórych LoAF. Dodatkowo, ponieważ wpisy z długimi klatkami animacji mogą być dość duże, deweloperzy powinni zdecydować, jakie dane z tego wpisu powinny być wysyłane do usługi Analytics. Na przykład podsumowanie czasu trwania wpisu i być może nazwy skryptów lub inny minimalny zestaw innych danych kontekstowych, które mogą być potrzebne.

Oto kilka sugerowanych wzorów, które pomogą Ci zmniejszyć ilość danych dotyczących długich klatek animacji:

Który z tych wzorów sprawdzi się najlepiej, zależy od tego, jak daleko zaawansowałeś/zaawansowałaś w optymalizacji i jak często występują długie klatki animacji. W przypadku witryny, która nigdy wcześniej nie była optymalizowana pod kątem responsywności, może być wiele elementów LoAF. Możesz ograniczyć się do elementów LoAF z interakcjami, ustawić wysoki próg lub analizować tylko najgorsze elementy.

Po rozwiązaniu typowych problemów z czasem reakcji możesz rozszerzyć te ustawienia, nie ograniczając się tylko do interakcji lub długich blokad lub obniżając wartości progowe.

Obserwuj długie klatki animacji z interakcjami

Aby uzyskać więcej informacji niż tylko długie ramki animacji INP, możesz sprawdzić wszystkie ramki LoAF z interakcjami (które można wykryć na podstawie obecności wartości firstUIEventTimestamp) o wysokiej wartości blockingDuration.

Może to być też łatwiejsza metoda monitorowania LoAF w ujęciu INP niż próba znalezienia korelacji między tymi dwoma wartościami, która może być bardziej skomplikowana. W większości przypadków obejmuje to czas trwania interakcji INP w przypadku danej wizyty, a w rzadkich przypadkach, gdy tak się nie dzieje, nadal wyświetla długie interakcje, które należy poprawić, ponieważ mogą być interakcjami INP w przypadku innych użytkowników.

Poniższy kod rejestruje wszystkie wpisy LoAF z wartością blockingDuration większą niż 100 ms, w przypadku których interakcja miała miejsce w ramach danej klatki. Wartość 100 została wybrana, ponieważ jest niższa niż „dobry” próg INP wynoszący 200 milisekund. Możesz wybrać wyższą lub niższą wartość w zależności od potrzeb.

const REPORTING_THRESHOLD_MS = 100;

const observer = new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    if (entry.blockingDuration > REPORTING_THRESHOLD_MS &&
      entry.firstUIEventTimestamp > 0
    ) {
      // Example here logs to console, but could also report back to analytics
      console.log(entry);
    }
  }
});
observer.observe({ type: 'long-animation-frame', buffered: true });

Obserwowanie długich klatek animacji z długim czasem blokowania

Zamiast sprawdzać wszystkie długie klatki animacji z interakcjami, możesz przyjrzeć się wszystkim długim klatkom animacji z długim czasem blokowania. Wskazują one na potencjalne problemy z INP, jeśli użytkownik wejdzie w interakcję podczas tych długich klatek animacji.

Poniższy kod rejestruje wszystkie wpisy LoAF z czasem blokowania dłuższym niż 100 ms, w przypadku których nastąpiła interakcja w ramach danej klatki. Wartość 100 wybrano, ponieważ jest ona mniejsza niż „dobry” próg INP wynoszący 200 ms, co pomaga zidentyfikować potencjalne klatki problemowe, a jednocześnie ogranicza do minimum liczbę zgłaszanych długich klatek animacji. Możesz wybrać wyższą lub niższą wartość w zależności od potrzeb.

const REPORTING_THRESHOLD_MS = 100;

const observer = new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    if (entry.blockingDuration > REPORTING_THRESHOLD_MS) {
      // Example here logs to console, but could also report back to analytics
      console.log(entry);
    }
  }
});
observer.observe({ type: 'long-animation-frame', buffered: true });

Obserwowanie długich klatek animacji podczas krytycznych aktualizacji interfejsu użytkownika w celu poprawy płynności

Jak już wspomnieliśmy, analiza ramek animacji o długim czasie blokowania może pomóc w zwiększeniu szybkości reakcji na dane wejściowe. Jednak aby sprawdzić płynność, należy przyjrzeć się wszystkim długim klatkom animacji z długim duration.

Ponieważ może to być dość trudne, warto ograniczyć pomiary do kluczowych punktów za pomocą poniższego wzorca:

const REPORTING_THRESHOLD_MS = 100;

const observer = new PerformanceObserver(list => {
  if (measureImportantUIupdate) {
    for (const entry of list.getEntries()) {
      if (entry.duration > REPORTING_THRESHOLD_MS) {
        // Example here logs to console, but could also report back to analytics
        console.log(entry);
      }
    }
  }
});
observer.observe({ type: 'long-animation-frame', buffered: true });

async function doUIUpdatesWithMeasurements() {
  measureImportantUIupdate = true;
  await doUIUpdates();
  measureImportantUIupdate = false;
}

Obserwowanie najgorszych długich klatek animacji

Zamiast ustawiać określony próg, witryny mogą zbierać dane o najdłuższym klatce animacji (lub klatkach), aby zmniejszyć ilość danych, które należy beaconować. Niezależnie od tego, ile klatek animacji jest wyświetlanych na stronie, z serwera beacona zwracane są tylko dane o najgorszych 5, 10 lub większej liczbie klatek animacji.

MAX_LOAFS_TO_CONSIDER = 10;
let longestBlockingLoAFs = [];

const observer = new PerformanceObserver(list => {
  longestBlockingLoAFs = longestBlockingLoAFs.concat(list.getEntries()).sort(
    (a, b) => b.blockingDuration - a.blockingDuration
  ).slice(0, MAX_LOAFS_TO_CONSIDER);
});
observer.observe({ type: 'long-animation-frame', buffered: true });

Strategie te można też łączyć – wystarczy przyjrzeć się 10 najgorszym LoAF z interakcjami dłuższymi niż 100 ms.

W odpowiednim momencie (najlepiej w zdarzeniu visibilitychange) beacon wraca do Analytics. Do testów lokalnych możesz okresowo używać console.table:

console.table(longestBlockingLoAFs);

Wykrywanie typowych wzorców w długich klatkach animacji

Inną strategią może być sprawdzenie najpopularniejszych skryptów w długich wpisach dotyczących ram animacji. Dane mogą być raportowane na poziomie skryptu i pozycji znaku, aby umożliwić identyfikację osób, które popełniają takie naruszenia wielokrotnie.

Może się to sprawdzić szczególnie w przypadku konfigurowalnych platform, na których można zidentyfikować motywy lub wtyczki powodujące problemy z wydajnością w wielu witrynach.

Czas wykonywania typowych skryptów lub skryptów pochodzących od innych firm w długich klatkach animacji można zsumować i przekazać w raportach, aby zidentyfikować elementy, które przyczyniają się do długich klatek animacji w całej witrynie lub w kolekcji witryn. Aby na przykład wyświetlić adresy URL:

const observer = new PerformanceObserver(list => {
  const allScripts = list.getEntries().flatMap(entry => entry.scripts);
  const scriptSource = [...new Set(allScripts.map(script => script.sourceURL))];
  const scriptsBySource= scriptSource.map(sourceURL => ([sourceURL,
      allScripts.filter(script => script.sourceURL === sourceURL)
  ]));
  const processedScripts = scriptsBySource.map(([sourceURL, scripts]) => ({
    sourceURL,
    count: scripts.length,
    totalDuration: scripts.reduce((subtotal, script) => subtotal + script.duration, 0)
  }));
  processedScripts.sort((a, b) => b.totalDuration - a.totalDuration);
  // Example here logs to console, but could also report back to analytics
  console.table(processedScripts);
});

observer.observe({type: 'long-animation-frame', buffered: true});

Przykład takich danych wyjściowych:

(index) sourceURL count totalDuration
0 'https://example.consent.com/consent.js' 1 840
1 'https://example.com/js/analytics.js' 7 628
2 'https://example.chatapp.com/web-chat.js' 1 5

Korzystanie z interfejsu Long Animation Frames API w narzędziach

Interfejs API umożliwia też korzystanie z dodatkowych narzędzi dla deweloperów do debugowania lokalnego. Chociaż niektóre narzędzia, takie jak Lighthouse i Narzędzie deweloperskie w Chrome, były w stanie zebrać wiele z tych danych, korzystając z szczegółów śledzenia na niższym poziomie, interfejs API na wyższym poziomie może umożliwić dostęp do tych danych innym narzędziom.

Wyświetlanie danych dotyczących długich klatek animacji w Narzędziach deweloperskich

Za pomocą interfejsu API performance.measure() możesz wyświetlać w narzędziach DevTools długie klatki animacji, które są następnie widoczne w śladzie Czasy użytkownika w narzędziach DevTools w śladach wydajności. Pozwala to określić, na czym należy się skupić, aby poprawić wydajność. Za pomocą interfejsu DevTools Extensibility API można nawet wyświetlać je na osobnej ścieżce:

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    performance.measure('LoAF', {
      start: entry.startTime,
      end: entry.startTime + entry.duration,
      detail: {
        devtools: {
          dataType: "track-entry",
          track: "Long animation frames",
          trackGroup: "Performance Timeline",
          color: "tertiary-dark",
          tooltipText: 'LoAF'
        }
      }
    });
  }
});

observer.observe({ type: 'long-animation-frame', buffered: true });
Ślad w panelu wydajności DevTools z niestandardową ścieżką zawierającą dane o długiej klatce animacji, które można porównać z główną wykresem słupkowym.
Wyświetlanie w Narzędziach deweloperskich danych dotyczących długiego klatki animacji.

W dłuższej perspektywie długie klatki animacji będą prawdopodobnie uwzględniane w Narzędziach deweloperskich, ale poprzedni fragment kodu umożliwia wyświetlanie ich w tym czasie.

Pierwszy wpis na poprzednim rysunku pokazuje też, gdzie przeglądarka przetworzyła kilka zadań w jednej długiej klatce animacji, zamiast renderować je osobno. Jak już wspomnieliśmy, może się tak zdarzyć, gdy nie ma zadań wejściowych o wysokim priorytecie, ale jest kolejka zadań. Pierwsze długie zadanie wymaga wykonania pewnych aktualizacji renderowania (w przeciwnym razie bieżąca długa klatka animacji zostanie zresetowana, a nowa rozpocznie się wraz z kolejnym zadaniem), ale zamiast natychmiast wykonać renderowanie, przeglądarka przetworzyła kilka dodatkowych zadań, a dopiero potem wykonała długie zadanie renderowania i zakończyła długą klatkę animacji. Pokazuje to, że warto sprawdzać długie klatki animacji w DevTools, a nie tylko długie zadania, aby wykrywać opóźnione renderowanie.

Używanie danych długich klatek animacji w innych narzędziach dla programistów

Rozszerzenie Web Vitals wyświetla wartość w podsumowaniu logowania w informacjach debugowania, aby diagnozować problemy z wydajnością.

Dane te obejmują teraz również dane o długich klatkach animacji w przypadku każdego wywołania zwrotnego INP i każdej interakcji:

Logowanie w konsoli rozszerzenia Web Vitals.
Logowanie rozszerzenia wskaźników internetowych w konsoli wyświetla dane LoAF.

Używanie danych o długich klatkach animacji w narzędziach do automatycznego testowania

Podobnie automatyczne narzędzia do testowania w pipelineach CI/CD mogą wyświetlać szczegóły dotyczące potencjalnych problemów ze skutecznością, mierząc długie klatki animacji podczas uruchamiania różnych zestawów testów.

Najczęstsze pytania

Oto kilka najczęstszych pytań dotyczących tego interfejsu API:

Może warto rozszerzyć lub iterować interfejs Long Tasks API?

Jest to inny sposób raportowania podobnego – ale ostatecznie innego – pomiaru potencjalnych problemów z reagowaniem. Ważne jest, aby witryny korzystające z obecnego interfejsu Long Tasks API nadal działały, aby nie zakłócać dotychczasowych zastosowań.

Chociaż interfejs Long Tasks API może korzystać z niektórych funkcji interfejsu Long Tasks for Audio (np. z lepszego modelu atrybucji), uważamy, że skupienie się na klatkach zamiast na zadaniach przynosi wiele korzyści, które sprawiają, że ten interfejs API różni się od dotychczasowego interfejsu Long Tasks API.

Dlaczego nie mam wpisów skryptu?

Może to oznaczać, że długa klatka animacji nie pochodzi z kodu JavaScipt, lecz z dużej ilości danych związanych z renderowaniem.

Zdarza się to również wtedy, gdy długa klatka animacji powstała z powodu JavaScriptu, ale nie można podać atrybucji skryptu z różnych powodów związanych z ochroną prywatności, jak wspomniano wcześniej (głównie kodu JavaScript nie należy do strony).

Dlaczego mam wpisy skryptu, ale nie mam informacji o źródle lub nie mam ich wcale?

Może się tak zdarzyć z wielu powodów, m.in. dlatego, że nie ma odpowiedniego źródła.

Informacje o skryptach będą też ograniczone w przypadku skryptów no-cors cross-origin, ale można je pobrać za pomocą CORS, dodając crossOrigin = "anonymous" do wywołania <script>.

Na przykład domyślny skrypt Menedżera tagów Google, który należy dodać do strony:

<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');</script>
<!-- End Google Tag Manager -->

Można go rozszerzyć, aby dodać j.crossOrigin = "anonymous", co umożliwi podanie pełnych szczegółów atrybucji w Google Tag Manager.

Czy to zastąpi interfejs Long Tasks API?

Uważamy, że interfejs Long Animation Frames API jest lepszym, bardziej kompletnym interfejsem do pomiaru długich zadań, ale obecnie nie planujemy wycofać interfejsu Long Tasks API.

Prośba o opinię

Opinie można przesyłać na liście problemów w GitHub. Błędy w implementacji interfejsu API w Chrome można zgłaszać za pomocą narzędzia do zgłaszania problemów w Chrome.

Podsumowanie

Interfejs Long Animation Frames API to nowy, ekscytujący interfejs API, który oferuje wiele potencjalnych zalet w porównaniu z poprzednim interfejsem Long Tasks API.

Okazuje się, że jest to kluczowe narzędzie do rozwiązywania problemów z szybkością reakcji, które są mierzone za pomocą INP. INP to dane, które trudno jest zoptymalizować, a ten interfejs API to jeden ze sposobów, w jaki zespół Chrome ułatwia programistom identyfikowanie i rozwiązywanie problemów.

Zakres interfejsu Long Animation Frames API wykracza jednak poza INP i może pomóc w wykrywaniu innych przyczyn powolnych aktualizacji, które mogą mieć wpływ na ogólną sprawność działania witryny.

Podziękowania

Miniatura autorstwa Henry Be z Unsplash.