API für Frames für lange Animationen

Die Long Animation Frames API (LoAF-ausgesprochen Lo-Af) ist ein Update für die Long Tasks API, um langsame Aktualisierungen der Benutzeroberfläche (UI) besser zu verstehen. Das kann hilfreich sein, um langsame Animationsframes zu identifizieren, die sich wahrscheinlich auf den Core Web Vital-Messwert Interaction to Next Paint (INP) auswirken, mit dem die Reaktionsfähigkeit gemessen wird, oder um andere Ruckler in der Benutzeroberfläche zu identifizieren, die sich auf die Glaubwürdigkeit auswirken.

Status der API

Unterstützte Browser

  • Chrome: 123.
  • Edge: 123.
  • Firefox: Nicht unterstützt.
  • Safari: Nicht unterstützt.

Quelle

Nach einem Ursprungstest von Chrome 116 bis Chrome 122 wurde die LoAF API ab Chrome 123 eingeführt.

Hintergrund: Long Tasks API

Unterstützte Browser

  • Chrome: 58.
  • Edge: 79.
  • Firefox: Nicht unterstützt.
  • Safari: Nicht unterstützt.

Quelle

Die Long Animation Frames API ist eine Alternative zur Long Tasks API, die seit Chrome 58 in Chrome verfügbar ist. Wie der Name schon sagt, können Sie mit der Long Task API lange Aufgaben überwachen, also Aufgaben, die den Haupt-Thread mindestens 50 Millisekunden lang belegen. Lange Aufgaben können über die PerformanceLongTaskTiming-Oberfläche mit einem PeformanceObserver überwacht werden:

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

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

Lange Aufgaben führen wahrscheinlich zu Problemen mit der Reaktionsfähigkeit. Wenn ein Nutzer versucht, mit einer Seite zu interagieren, z. B. auf eine Schaltfläche zu klicken oder ein Menü zu öffnen, der Hauptthread aber bereits mit einer langen Aufgabe beschäftigt ist, wird die Interaktion des Nutzers verzögert, bis diese Aufgabe abgeschlossen ist.

Um die Reaktionsfähigkeit zu verbessern, wird oft empfohlen, lange Aufgaben aufzuteilen. Wenn jede lange Aufgabe stattdessen in eine Reihe mehrerer, kleinerer Aufgaben aufgeteilt wird, können wichtigere Aufgaben zwischen ihnen ausgeführt werden, um erhebliche Verzögerungen bei der Reaktion auf Interaktionen zu vermeiden.

Wenn Sie also die Reaktionsfähigkeit verbessern möchten, besteht der erste Anhaltspunkt oft darin, eine Leistungs-Trace auszuführen und sich lange Aufgaben anzusehen. Das kann über ein Lab-basiertes Auditing-Tool wie Lighthouse (mit der Prüfung Lange Hauptthreadaufgaben vermeiden) oder durch Ansehen langer Aufgaben in den Chrome-Entwicklertools erfolgen.

Labbasierte Tests sind häufig ein schlechter Ausgangspunkt, um Probleme mit der Reaktionsfähigkeit zu erkennen, da diese Tools möglicherweise keine Interaktionen enthalten. Wenn sie dies tun, stellen sie einen kleinen Teil der wahrscheinlichen Interaktionen dar. Im Idealfall sollten Sie die Ursachen für langsame Interaktionen vor Ort messen.

Nachteile der Long Tasks API

Das Messen langer Aufgaben im Feld mit einem Leistungs-Observer ist nur bedingt sinnvoll. In Wirklichkeit gibt es nicht viele Informationen darüber, außer dass eine lange Aufgabe stattgefunden hat und wie lange sie gedauert hat.

Mithilfe von Real User Monitoring (RUM)-Tools werden häufig Trends bei der Anzahl oder Dauer langer Aufgaben ermittelt oder die Seiten identifiziert, auf denen sie auftreten. Ohne die zugrunde liegenden Details zur Ursache der langen Aufgabe ist dies jedoch nur von begrenztem Nutzen. Die Long Tasks API hat nur ein einfaches Attributionsmodell, das bestenfalls nur den Container angibt, in dem die lange Aufgabe ausgeführt wurde (das Dokument der obersten Ebene oder eine <iframe>), aber nicht das Script oder die Funktion, die sie aufgerufen hat. Das ist an einem typischen Eintrag zu sehen:

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

Die Long Tasks API ist ebenfalls unvollständig, da einige wichtige Aufgaben möglicherweise ausgeschlossen werden. Einige Aktualisierungen, z. B. das Rendering, erfolgen in separaten Aufgaben, die idealerweise zusammen mit der vorherigen Ausführung, die diese Aktualisierung verursacht hat, enthalten sein sollten, um die „Gesamtarbeit“ für diese Interaktion genau zu messen. Weitere Informationen zu den Einschränkungen, die sich aus der Abhängigkeit von Aufgaben ergeben, finden Sie im Abschnitt Wozu lange Aufgaben bestehen? der Erklärung.

Das letzte Problem ist, dass bei der Messung langer Aufgaben nur einzelne Aufgaben erfasst werden, die länger als 50 Millisekunden dauern. Ein Animationsframe kann aus mehreren Aufgaben bestehen, die kürzer als 50 Millisekunden sind, aber gemeinsam das Rendern des Browsers blockieren.

Long Animation Frames API

Unterstützte Browser

  • Chrome: 123.
  • Edge: 123.
  • Firefox: Nicht unterstützt.
  • Safari: Nicht unterstützt.

Quelle

Die Long Animation Frames API (LoAF) ist eine neue API, mit der einige der Mängel der Long Tasks API behoben werden sollen. So erhalten Entwickler umsetzbarere Informationen, um Probleme mit der Reaktionsfähigkeit zu beheben und die INP zu verbessern. Außerdem erhalten sie Informationen zu Problemen mit der Laufruhe.

Eine gute Reaktionsfähigkeit bedeutet, dass eine Seite schnell auf Interaktionen reagiert. Dazu gehört, dass Sie alle vom Nutzer benötigten Updates rechtzeitig darstellen und vermeiden können, dass diese Updates blockiert werden. Für INP wird eine Reaktionszeit von maximal 200 Millisekunden empfohlen. Bei anderen Aktualisierungen (z. B. Animationen) sind aber selbst 200 Millisekunden möglicherweise zu lang.

Die Long Animation Frames API ist eine alternative Methode zur Messung blockierender Arbeit. Anstatt die einzelnen Aufgaben zu messen, werden mit der Long Animation Frames API – wie der Name schon sagt – lange Animationsframes gemessen. Ein langer Animationsframe liegt vor, wenn eine Renderingaktualisierung länger als 50 Millisekunden verzögert ist (derselbe Grenzwert wie für die Long Tasks API).

Lange Animationsframes werden ab dem Beginn von Aufgaben gemessen, die ein Rendern erfordern. Wenn für die erste Aufgabe in einem potenziellen langen Animationsframe kein Rendern erforderlich ist, wird der lange Animationsframe nach Abschluss der Aufgabe ohne Rendering beendet und ein neuer potenzieller langer Animationsframe mit der nächsten Aufgabe gestartet. Solche nicht rendernden langen Animationsframes sind immer noch in der Long Animation Frames API enthalten, wenn sie länger als 50 Millisekunden (mit einer renderStart-Zeit von 0) sind, um die Messung der potenziell blockierenden Arbeit zu ermöglichen.

Lange Animationsframes können ähnlich wie lange Aufgaben mit einem PerformanceObserver beobachtet werden, wobei stattdessen der Typ long-animation-frame betrachtet wird:

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

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

So können Sie auch vorherige lange Animationsframes aus der Leistungszeitachse abfragen:

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

Es gibt jedoch eine maxBufferSize für Leistungseinträge, nach der neuere Einträge gelöscht werden. Daher wird der PerformanceObserver-Ansatz empfohlen. Die Puffergröße für long-animation-frame ist auf 200 festgelegt, genau wie für long-tasks.

Vorteile der Betrachtung von Frames anstelle von Aufgaben

Der Hauptvorteil dieser Betrachtungsweise aus der Perspektive des Frames statt der Aufgaben besteht darin, dass eine lange Animation aus beliebig vielen Aufgaben bestehen kann, die zusammen zu einem langen Animationsframe führen. Dies behebt den letzten oben genannten Punkt, bei dem die Summe vieler kleinerer, renderblockierender Aufgaben vor einem Animationsframe möglicherweise nicht von der Long Tasks API erfasst wird.

Ein weiterer Vorteil dieser alternativen Ansicht für lange Aufgaben ist die Möglichkeit, eine Aufschlüsselung der Zeit für den gesamten Frame bereitzustellen. Anstatt nur startTime und duration wie bei der Long Tasks API enthält LoAF eine viel detailliertere Aufschlüsselung der verschiedenen Teile der Framedauer.

Zeitstempel und Dauer von Frames

  • startTime: die Startzeit des langen Animationsframes relativ zur Navigationsstartzeit.
  • duration: die Dauer des langen Animationsframes (ohne Präsentationszeit).
  • renderStart: die Startzeit des Rendering-Zyklus, einschließlich requestAnimationFrame-Callbacks, Stil- und Layoutberechnung, Resize-Observer- und Intersection-Observer-Callbacks.
  • styleAndLayoutStart: Der Beginn des Zeitraums, in dem Stil- und Layoutberechnungen ausgeführt wurden.
  • firstUIEventTimestamp: die Zeit des ersten UI-Ereignisses (Maus/Tastatur usw.), das im Verlauf dieses Frames verarbeitet werden soll.
  • blockingDuration: die Gesamtdauer in Millisekunden, für die der Animationsframe die Verarbeitung von Eingaben oder anderen Aufgaben mit hoher Priorität blockiert.

Eine Erklärung zu blockingDuration

Ein langer Animationsframe kann aus mehreren Aufgaben bestehen. blockingDuration ist die Summe der Aufgabendauern, die länger als 50 Millisekunden sind, einschließlich der endgültigen Renderingdauer innerhalb der längsten Aufgabe.

Wenn ein langer Animationsframe beispielsweise aus zwei Aufgaben mit 55 Millisekunden und 65 Millisekunden besteht, gefolgt von einem Rendern von 20 Millisekunden, beträgt die duration etwa 140 Millisekunden mit einer blockingDuration von (55 − 50) + (65 + 20 − 50) = 40 Millisekunden. Während dieses 140 Millisekunden langen Animationsframes wurde der Frame 40 Millisekunden lang als blockiert für die Verarbeitung von Eingaben betrachtet.

Ob duration oder blockingDuration betrachtet werden soll

Bei einem 60-Hertz-Display versucht ein Browser, mindestens alle 16,66 Millisekunden einen Frame zu planen (um flüssige Updates zu ermöglichen) oder nach einer Aufgabe mit hoher Priorität wie der Eingabeverarbeitung (um responsive Updates zu ermöglichen). Wenn es jedoch keine Eingaben und keine anderen Aufgaben mit hoher Priorität gibt, aber eine Warteschlange mit anderen Aufgaben vorhanden ist, führt der Browser den aktuellen Frame in der Regel weit über 16,66 Millisekunden hinaus fort, unabhängig davon, wie gut die Aufgaben darin aufgeteilt sind. Das heißt, der Browser versucht immer, Eingaben zu priorisieren, kann aber auch eine Aufgabenliste anstelle von Rendering-Aktualisierungen bearbeiten. Das liegt daran, dass das Rendering ein kostspieliger Prozess ist. Daher führt die Verarbeitung einer kombinierten Rendering-Aufgabe für mehrere Aufgaben in der Regel zu einer Gesamtreduzierung des Arbeitsaufwands.

Daher sollten lange Animationsframes mit einem niedrigen oder nullwertigen blockingDuration immer noch reaktionsschnell auf Eingaben reagieren. Das Reduzieren oder Entfernen von blockingDuration durch Aufteilen langer Aufgaben ist daher entscheidend, um die Reaktionsfähigkeit gemäß INP-Messung zu verbessern.

Viele lange Animationsframes, unabhängig von blockingDuration, deuten jedoch auf verzögerte UI-Aktualisierungen hin, die sich dennoch auf die Laufruhe auswirken und zu einer verzögerten Benutzeroberfläche beim Scrollen oder bei Animationen führen können, auch wenn dies für die Reaktionsfähigkeit, gemessen anhand des INP, weniger problematisch ist. Um Probleme in diesem Bereich zu verstehen, sehen Sie sich die duration an. Diese lassen sich jedoch schwieriger optimieren, da Sie das Problem nicht durch Aufteilen der Arbeit lösen können, sondern die Arbeit reduzieren müssen.

Frame-Timings

Mit den zuvor erwähnten Zeitstempeln kann der lange Animationsframe in Zeiträume unterteilt werden:

Timing Berechnung
Beginn startTime
Ende startTime + duration
Arbeitsdauer renderStart ? renderStart - startTime : duration
Renderingdauer renderStart ? (startTime + duration) - renderStart: 0
Rendern: Dauer vor dem Layout styleAndLayoutStart ? styleAndLayoutStart - renderStart : 0
Rendering: Stil und Layoutdauer styleAndLayoutStart ? (startTime + duration) - styleAndLayoutStart : 0

Bessere Scriptzuordnung

Der long-animation-frame-Eintragstyp enthält bessere Attributionsdaten für jedes Script, das zu einem langen Animationsframe beigetragen hat (für Scripts, die länger als 5 Millisekunden sind).

Ähnlich wie bei der Long Tasks API wird diese in einem Array von Attributionseinträgen bereitgestellt, die jeweils folgende Details enthalten:

  • Sowohl name als auch EntryType geben script zurück.
  • Eine aussagekräftige invoker, die angibt, wie das Script aufgerufen wurde (z. B. 'IMG#id.onload', 'Window.requestAnimationFrame' oder 'Response.json.then').
  • Die invokerType des Script-Einstiegspunkts:
    • user-callback: Ein bekannter Callback, der über eine Webplattform-API registriert wurde (z. B. setTimeout, requestAnimationFrame).
    • event-listener: Ein Listener für ein Plattformereignis (z. B. click, load, keyup).
    • resolve-promise: Handler eines Plattformversprechens (z. B. fetch(). Im Fall von Promis werden alle Handler derselben Promis als ein Script zusammengeführt..
    • reject-promise: Wie bei resolve-promise, aber für die Ablehnung.
    • classic-script: Scriptauswertung (z. B. <script> oder import())
    • module-script: Entspricht classic-script, aber für Modulscripts.
  • Separate Zeitdaten für das Skript:
    • startTime: Zeitpunkt, zu dem die Eintragsfunktion aufgerufen wurde.
    • duration: Der Zeitraum zwischen dem startTime und dem Zeitpunkt, zu dem die Verarbeitung der nachfolgenden Microtask-Warteschlange abgeschlossen ist.
    • executionStart: Die Zeit nach der Kompilierung.
    • forcedStyleAndLayoutDuration: Die Gesamtzeit, die für die Verarbeitung des erzwungenen Layouts und Stils in dieser Funktion aufgewendet wird (siehe Überlastung).
    • pauseDuration: Gesamtzeit, die für die Pausierung synchroner Vorgänge (Benachrichtigung, synchrone XHR) aufgewendet wurde.
  • Details zur Skriptquelle:
    • sourceURL: Der Name der Scriptressource, sofern verfügbar (leer, wenn nicht gefunden).
    • sourceFunctionName: Der Name der Scriptfunktion, sofern verfügbar (leer, wenn nicht gefunden).
    • sourceCharPosition: Die Zeichenposition des Skripts, falls verfügbar (oder -1, wenn sie nicht gefunden wurde).
  • windowAttribution: Der Container (das Dokument auf oberster Ebene oder ein <iframe>), in dem der lange Animationsframe aufgetreten ist.
  • window: Eine Referenz auf das Fenster mit demselben Ursprung.

Sofern angegeben, können Entwickler mithilfe der Quelleinträge genau nachvollziehen, wie jedes Skript im langen Animationsframe bis zur Zeichenposition im aufrufenden Skript aufgerufen wurde. Hier sehen Sie den genauen Speicherort in einer JavaScript-Ressource, der zu dem langen Animationsframe geführt hat.

Beispiel für einen long-animation-frame-Leistungseintrag

Hier ein vollständiges Beispiel für einen long-animation-frame-Leistungseintrag mit einem einzelnen Script:

{
  "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
}

Wie Sie sehen, erhalten Sie so eine nie dagewesene Menge an Daten, mit denen Sie die Ursache für verzögerte Rendering-Aktualisierungen ermitteln können.

Long Animation Frames API im Feld verwenden

Tools wie die Chrome-Entwicklertools und Lighthouse sind zwar nützlich, um Probleme zu erkennen und zu reproduzieren, aber sie sind Lab-Tools, die wichtige Aspekte der Nutzererfahrung übersehen können, die nur Felddaten liefern können.

Die Long Animation Frames API wurde entwickelt, um wichtige Kontextdaten für Nutzerinteraktionen zu erfassen, die mit der Long Tasks API nicht möglich sind. So können Sie Probleme bei der Interaktivität identifizieren und reproduzieren, die Ihnen sonst möglicherweise nicht aufgefallen wären.

Unterstützung der API für die Funktion zur Erkennung langer Frames bei Animationen

Mit dem folgenden Code kannst du testen, ob die API unterstützt wird:

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

Der offensichtlichste Anwendungsfall für die Long Animation Frames API besteht darin, Probleme mit der Interaktion bis zur nächsten Darstellung (Interaction to Next Paint, INP) zu diagnostizieren und zu beheben. Dies war einer der Hauptgründe, warum das Chrome-Team diese API entwickelt hat. Bei einem guten INP werden alle Interaktionen innerhalb von 200 Millisekunden nach der Interaktion bis zur Darstellung des Frames verarbeitet. Da die Long Animation Frames API alle Frames misst, die mindestens 50 Millisekunden dauern, sollten die meisten problematischen INPs LoAF-Daten enthalten, damit Sie diese Interaktionen diagnostizieren können.

Die „INP LoAF“ ist das LoAF, das die INP-Interaktion enthält, wie im folgenden Diagramm dargestellt:

Beispiele für lange Animationsframes auf einer Seite, wobei der INP-LoAF hervorgehoben ist.
Eine Seite kann viele LoAFs haben, von denen eine mit der INP-Interaktion zusammenhängt.

In einigen Fällen ist es möglich, dass ein INP-Ereignis zwei LoAFs umfasst. Dies geschieht normalerweise, wenn die Interaktion erfolgt, nachdem der Frame das Rendering des vorherigen Frames gestartet hat und der Event-Handler im nächsten Frame verarbeitet wird:

Beispiele für lange Animationsframes auf einer Seite, wobei der INP-LoAF hervorgehoben ist.
Eine Seite kann viele LoAFs haben, von denen eines mit der INP-Interaktion zusammenhängt.

In seltenen Fällen kann es sogar mehr als zwei LoAFs umfassen.

Wenn Sie die Daten der LoAFs erfassen, die mit der INP-Interaktion verknüpft sind, erhalten Sie viel mehr Informationen zur INP-Interaktion, die Ihnen bei der Diagnose helfen. Das ist besonders hilfreich, um die Eingabeverzögerung zu verstehen, da Sie sehen können, welche anderen Scripts in diesem Frame ausgeführt wurden.

Es kann auch hilfreich sein, die unerklärlichen Verarbeitungsdauer und Verzögerungen bei der Präsentation zu verstehen, wenn Ihre Event-Handler die für diese erfassten Werte nicht reproduzieren, da möglicherweise andere Skripts für Ihre Nutzer ausgeführt werden, die möglicherweise nicht in Ihren eigenen Tests enthalten sind.

Es gibt keine direkte API, um einen INP-Eintrag mit den zugehörigen LoAF-Einträgen zu verknüpfen. Es ist jedoch möglich, dies im Code zu tun, indem die Start- und Endzeiten der einzelnen Einträge verglichen werden (siehe Beispielscript für WhyNp). Die web-vitals-Bibliothek enthält alle sich überschneidenden LoAFs in der longAnimationFramesEntries-Property der INP-Attributionsoberfläche ab Version 4.

Nachdem Sie den oder die LoAF-Einträge verknüpft haben, können Sie Informationen mit der INP-Zuordnung hinzufügen. Das scripts-Objekt enthält einige der wertvollsten Informationen, da es zeigen kann, was sonst in diesen Frames lief. Durch das Beaconing dieser Daten an Ihren Analysedienst können Sie also besser nachvollziehen, warum Interaktionen langsam waren.

Wenn Sie LoAFs für die INP-Interaktion melden, können Sie die dringendsten Interaktivitätsprobleme auf Ihrer Seite ermitteln. Jeder Nutzer kann unterschiedlich mit Ihrer Seite interagieren. Bei ausreichender Datenmenge für die Attribution über indirekte Zugriffe sind einige potenzielle Probleme in den Daten enthalten. So können Sie Scripts nach Volumen sortieren, um zu sehen, welche Scripts mit einer langsamen INP korrelieren.

Längere Animationsdaten an einen Analyseendpunkt zurückgeben

Ein Nachteil der ausschließlichen Betrachtung der INP-LoAFs besteht darin, dass Sie möglicherweise andere potenzielle Verbesserungsmöglichkeiten übersehen, die zu zukünftigen INP-Problemen führen können. Das kann dazu führen, dass Sie das Gefühl haben, im Kreis zu laufen, wenn Sie ein INP-Problem beheben und eine große Verbesserung erwarten, nur um festzustellen, dass die nächste langsamste Interaktion nur geringfügig besser ist, sodass sich Ihr INP nicht wesentlich verbessert.

Anstatt sich nur auf den INP-LoAF zu konzentrieren, sollten Sie alle LoAFs über die gesamte Lebensdauer der Seite hinweg berücksichtigen:

Eine Seite mit vielen LoAFs, von denen einige während Interaktionen auftreten, auch wenn es sich nicht um die INP-Interaktion handelt.
Ein Blick auf alle LoAFs kann dabei helfen, zukünftige INP-Probleme zu erkennen.

Jeder LoAF-Eintrag enthält jedoch erhebliche Daten. Daher sollten Sie Ihre Analyse wahrscheinlich auf einige LoAFs beschränken. Da die Einträge für lange Animationsframes außerdem recht groß sein können, sollten Entwickler entscheiden, welche Daten aus dem Eintrag an Analytics gesendet werden sollen. Dazu gehören beispielsweise die Zusammenfassungszeiten des Eintrags und möglicherweise die Scriptnamen oder andere Mindestmengen an anderen Kontextdaten, die als erforderlich erachtet werden.

Hier einige Vorschläge, wie Sie die Menge der Daten für lange Animationsframes reduzieren können:

Welches dieser Muster am besten für Sie geeignet ist, hängt davon ab, wie weit Sie mit der Optimierung fortgeschritten sind und wie häufig lange Animationsframes vorkommen. Bei einer Website, die noch nie für die Responsivität optimiert wurde, kann es viele LoAFs geben. Sie können sich auf LoAFs mit Interaktionen beschränken, einen hohen Grenzwert festlegen oder sich nur die schlechtesten ansehen.

Wenn Sie die häufigsten Probleme mit der Reaktionsfähigkeit behoben haben, können Sie die Funktion erweitern, indem Sie sie nicht nur auf Interaktionen oder lange Blockierungsdauern beschränken oder die Grenzwerte senken.

Lange Animationsframes mit Interaktionen beobachten

Um Informationen über den INP-Frame für lange Animationen hinaus zu erhalten, können Sie sich alle LoAFs mit Interaktionen (die durch das Vorhandensein eines firstUIEventTimestamp-Werts erkannt werden) mit einem hohen blockingDuration ansehen.

Dies kann auch eine einfachere Methode zur Überwachung der INP-LoAFs sein, anstatt zu versuchen, die beiden zu korrelieren, was komplexer sein kann. In den meisten Fällen ist dies die LoAF für die Interaktion mit dem INP für einen bestimmten Besuch. In seltenen Fällen, in denen dies nicht der Fall ist, werden trotzdem lange Interaktionen angezeigt, die behoben werden müssen, da sie möglicherweise die Interaktion mit dem INP für andere Nutzer ist.

Der folgende Code protokolliert alle LoAF-Einträge mit einer blockingDuration von mehr als 100 Millisekunden, bei denen während des Frames eine Interaktion stattgefunden hat. Die 100 wird hier ausgewählt, da sie unter dem INP-Grenzwert von 200 Millisekunden liegt. Je nach Bedarf können Sie einen höheren oder niedrigeren Wert auswählen.

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

Lange Animationsframes mit hoher Blockierungsdauer beobachten

Anstatt sich alle langen Frames mit Interaktionen anzusehen, sollten Sie sich alle langen Frames mit langen Blockierungsdauern ansehen. Diese geben Aufschluss über potenzielle INP-Probleme, wenn ein Nutzer während dieser langen Animationsframes interagiert.

Mit dem folgenden Code werden alle LoAF-Einträge mit einer Blockierdauer von mehr als 100 Millisekunden protokolliert, bei denen während des Frames eine Interaktion stattfand. Die Zahl 100 wird hier ausgewählt, da sie unter dem INP-Grenzwert von 200 Millisekunden liegt, um potenzielle Problemframes zu identifizieren und gleichzeitig die Anzahl der gemeldeten langen Animationsframes auf ein Minimum zu beschränken. Sie können je nach Ihren Anforderungen einen höheren oder niedrigeren Wert wählen.

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

Lange Animationsframes bei wichtigen UI-Änderungen beobachten, um die Laufruhe zu verbessern

Wie bereits erwähnt, kann die Prüfung langer Frames mit hoher Blockierungsdauer dazu beitragen, die Eingabereaktion zu verbessern. Für eine flüssige Animation sollten Sie sich jedoch alle langen Animationsframes mit einer langen duration ansehen.

Da dies zu sehr ungenauen Ergebnissen führen kann, sollten Sie die Messungen auf wichtige Punkte mit einem Muster wie diesem beschränken:

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

Die schlechtesten Long-Animation-Frames beobachten

Anstatt einen Grenzwert festzulegen, können Websites Daten für den längsten Animationsframe (oder Frames) erfassen, um das Volumen der Daten zu reduzieren, die per Beacon gesendet werden müssen. Unabhängig davon, wie viele lange Animationsframes auf einer Seite vorhanden sind, werden nur Daten für die fünf, zehn oder wie viele langen Animationsframes auch immer absolut notwendig sind, zurückgesendet.

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

Diese Strategien können auch kombiniert werden. Sehen Sie sich nur die zehn schlechtesten LoAFs mit Interaktionen an, die länger als 100 Millisekunden dauern.

Senden Sie das Beacon zum richtigen Zeitpunkt (idealerweise beim visibilitychange-Ereignis) zurück an Analytics. Für lokale Tests können Sie console.table regelmäßig verwenden:

console.table(longestBlockingLoAFs);

Gängige Muster in langen Animationsframes identifizieren

Eine alternative Strategie wäre, sich gängige Scripts anzusehen, die am häufigsten in langen Animationsframe-Einträgen vorkommen. Daten können auf Skript- und Zeichenpositionsebene gemeldet werden, um Wiederholungstäter zu identifizieren.

Das funktioniert möglicherweise besonders gut für anpassbare Plattformen, auf denen Themen oder Plug-ins, die Leistungsprobleme verursachen, auf einer Reihe von Websites identifiziert werden können.

Die Ausführungszeit gängiger Scripts oder Drittanbieter-Quellen in langen Animationsframes kann summiert und zurückgemeldet werden, um häufige Ursachen für lange Animationsframes auf einer Website oder einer Gruppe von Websites zu identifizieren. So können Sie sich beispielsweise URLs ansehen:

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

Ein Beispiel für diese Ausgabe:

(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

Long Animation Frames API in Tools verwenden

Die API bietet auch zusätzliche Entwicklertools für das lokale Debugging. Mit einigen Tools wie Lighthouse und den Chrome-Entwicklertools konnten zwar viele dieser Daten mit Low-Level-Tracing-Details erhoben werden, aber mit dieser übergeordneten API könnten andere Tools auf diese Daten zugreifen.

Daten zu langen Animationsframes in den Entwicklertools ansehen

Mit der performance.measure() API können Sie lange Animationsframes in den DevTools anzeigen lassen. Diese werden dann in Leistungsaufzeichnungen im DevTools-Nutzerzeit-Track angezeigt, um zu zeigen, wo Sie sich auf Leistungsverbesserungen konzentrieren sollten. Mit der DevTools Extensibility API können diese sogar in einem eigenen Track angezeigt werden:

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 });
DevTools-Leistungspanel-Trace mit einem benutzerdefinierten Track, der Daten zu langen Animationsframes enthält, die mit dem Haupt-Flaschendiagramm verglichen werden können.
Lange Animationsframe-Daten in den DevTools anzeigen

Langfristig werden lange Animationsframes wahrscheinlich in die DevTools selbst eingebunden. Mit dem vorherigen Code-Snippet können sie aber in der Zwischenzeit dort angezeigt werden.

Der erste Eintrag in der vorherigen Abbildung zeigt ebenfalls, wo der Browser mehrere Aufgaben zusammen im selben langen Animationsframe verarbeitet hat, anstatt zwischen ihnen zu rendern. Wie bereits erwähnt, kann dies passieren, wenn es keine Eingabeaufgaben mit hoher Priorität, aber eine Warteschlange mit Aufgaben gibt. Für die erste lange Aufgabe müssen einige Rendering-Aktualisierungen ausgeführt werden (andernfalls wird der aktuelle lange Animationsframe im Anschluss zurückgesetzt und mit der nächsten Aufgabe ein neuer gestartet). Statt sofort zu rendern, hat der Browser eine Reihe zusätzlicher Aufgaben verarbeitet, erst dann die lange Rendering-Aufgabe ausgeführt und den langen Animationsframe beendet. Das zeigt, wie nützlich es ist, sich in den DevTools lange Animationsframes anzusehen, anstatt nur lange Aufgaben, um verzögerte Renderings zu identifizieren.

Daten zu langen Animationsframes in anderen Entwicklertools verwenden

Die Web Vitals-Erweiterung hat den Wert in den Debug-Informationen der Zusammenfassungszusammenfassung angezeigt, um Leistungsprobleme zu diagnostizieren.

Außerdem werden jetzt Daten zu langen Animationsframes für jeden INP-Callback und jede Interaktion angezeigt:

Console-Logging der Web Vitals-Erweiterung
In der Konsole der Web Vitals-Erweiterung werden LoAF-Daten protokolliert.

Daten zu langen Animationsframes in automatisierten Testtools verwenden

Ähnlich können automatisierte Testtools in CI/CD-Pipelines Details zu potenziellen Leistungsproblemen aufzeigen, indem lange Animationsframes während der Ausführung verschiedener Test-Suites gemessen werden.

FAQ

Zu den häufig gestellten Fragen zu dieser API gehören:

Warum nicht einfach die Long Tasks API erweitern oder iterieren?

Dies ist eine alternative Möglichkeit, eine ähnliche, aber letztendlich andere Messung potenzieller Probleme mit der Reaktionsfähigkeit zu erfassen. Es ist wichtig, dass Websites, die auf die bestehende Long Tasks API angewiesen sind, weiterhin funktionieren, um Unterbrechungen bestehender Anwendungsfälle zu vermeiden.

Die Long Tasks API kann zwar von einigen der Funktionen von LoAF profitieren (z. B. einem besseren Attributionsmodell), wir sind jedoch der Meinung, dass der Fokus auf Frames statt auf Aufgaben viele Vorteile bietet, die diese API grundlegend von der bestehenden Long Tasks API unterscheiden.

Why do I not have script entries?

Dies kann darauf hindeuten, dass der lange Animationsframe nicht auf JavaScript, sondern auf eine große Menge an Rendering zurückzuführen ist.

Das kann auch passieren, wenn der lange Animationsframe auf JavaScript zurückzuführen ist, die Script-Attribution aber aus verschiedenen Datenschutzgründen, wie bereits erwähnt, nicht angegeben werden kann (vor allem, wenn das JavaScript nicht der Seite gehört).

Warum habe ich Scripteinträge, aber keine oder nur wenige Quelleninformationen?

Das kann verschiedene Gründe haben, z. B. dass keine gute Quelle angegeben wurde.

Für no-cors cross-origin-Scripts sind ebenfalls nur begrenzte Skriptinformationen verfügbar. Das Problem lässt sich jedoch beheben, indem Sie diese Scripts mit CORS abrufen. Fügen Sie dazu dem <script>-Aufruf crossOrigin = "anonymous" hinzu.

Hier sehen Sie beispielsweise das standardmäßige Google Tag Manager-Skript, das Sie der Seite hinzufügen möchten:

<!-- 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 -->

Kann durch Hinzufügen von j.crossOrigin = "anonymous" erweitert werden, um vollständige Attributionsdetails für GTM bereitzustellen

Wird die Long Tasks API dadurch ersetzt?

Wir sind der Meinung, dass die Long Animation Frames API eine bessere, umfassendere API für die Messung langer Aufgaben ist. Derzeit ist jedoch nicht geplant, die Long Tasks API einzustellen.

Feedback erwünscht

Feedback können Sie über die GitHub-Problemliste geben. Fehler bei der Implementierung der API in Chrome können Sie über die Problemverfolgung von Chrome melden.

Fazit

Die Long Animation Frames API ist eine spannende neue API mit vielen potenziellen Vorteilen gegenüber der vorherigen Long Tasks API.

Es erweist sich als wichtiges Tool zur Behebung von Problemen mit der Reaktionsfähigkeit, gemessen am INP. Der Messwert „INP“ lässt sich nur schwer optimieren. Mit dieser API möchte das Chrome-Team Entwicklern die Identifizierung und Behebung von Problemen erleichtern.

Der Umfang der Long Animation Frames API geht jedoch über INP hinaus und kann helfen, andere Ursachen für langsame Aktualisierungen zu identifizieren, die sich auf die allgemeine Nutzerfreundlichkeit einer Website auswirken können.

Danksagungen

Miniaturansicht von Henry Be auf Unsplash.