Long Animation Frames API: INP in Produktion debuggen

Ein Produktions-Playbook, um das Script zu finden, das Ihre Interaktion beeinträchtigt hat

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2026-04-30

Jahrelang wurde die Frage "Was verursacht meinen INP?" oft mit einem verständnislosen Blick beantwortet. Die Long Tasks API sagte Ihnen, dass der Main Thread für mehr als 50ms blockiert war. Sie sagte Ihnen nicht, welches Script. Sie sagte Ihnen nicht, in welcher Zeile. Alles, was wir hatten, war eine Zahl in ms.

Die Long Animation Frames API behebt das. Sie ist seit Chrome 123 in Chromium-Browsern verfügbar und gibt Ihnen die vollständige Anatomie eines Frames: Gesamtdauer, Blockierungsdauer, der Moment, in dem der Renderer startete, der Moment, in dem Style und Layout begannen, und ein Array jedes Scripts, das länger als 5ms im Frame lief. Jeder Script-Eintrag enthält die Quell-URL, den Funktionsnamen, die Zeichenposition in der Datei und die Art des Callbacks, der es aufgerufen hat.

Dies sind die Daten, die das INP-Debugging immer brauchte. Der Rest dieses Artikels handelt davon, wie man sie auf einer echten Produktions-Website nutzt, ohne die Dinge zu verschlimmern.

Diese Seite ist Teil unserer Interaction to Next Paint (INP)-Serie. Das untenstehende LoAF-Playbook führe ich aus, nachdem ich die Metrik diagnostiziert habe. Wenn INP neu für Sie ist, beginnen Sie mit den drei Phasen-Leitfäden für input delay, processing time und presentation delay sowie dem breiteren find-and-fix INP-Workflow.

Warum Long Tasks nicht ausreichten

Ein Long Task wird ausgelöst, wenn ein einzelner Task auf dem Main Thread länger als 50ms läuft. Das ist nützlich, um die offensichtlichen Blocker zu finden. Es ist nutzlos für INP, da die meisten langsamen Interaktionen nicht ein einzelner Long Task sind. Sie sind eine Sequenz von mittleren Tasks plus einem langen Render.

Eine Interaktion kann bei INP durchfallen, ohne jemals einen Long Task auszulösen. Ein 40ms Event-Handler, gefolgt von einer 70ms Style-Neuberechnung, summiert sich auf 110ms Presentation Delay. Die Long Tasks API meldet nichts. Der Nutzer spürt die Verzögerung.

Der andere Fehler von Long Tasks ist die Attribution. Sie erhalten einen Containertyp, einen Containernamen und ein Namensfeld, das Ihnen sagt, ob der Long Task "self", "same-origin-ancestor", "same-origin-descendant", "unknown" oder eine von wenigen Cross-Origin-Varianten war. Sie erhalten nicht das Script, das gelaufen ist. Selbst wenn Sie also einen Long Task abfangen, müssen Sie immer noch die DevTools öffnen und die Interaktion neu aufzeichnen, um die Ursache zu finden. Das funktioniert im Labor. Es funktioniert nicht für INP bei echten Nutzern, die Sie nicht reproduzieren können.

LoAF ersetzt diese beiden Einschränkungen. Es erfasst den gesamten Frame, nicht einen einzelnen Task. Und es sagt Ihnen genau, welches Script gelaufen ist, nach URL und Funktionsnamen.

Die sieben wichtigsten Felder

Ein LoAF-Eintrag hat mehr Felder, als Sie benötigen. Diese sieben sind diejenigen, die ich zuerst lese, wenn ich eine Interaktion debugge.

duration ist die Gesamtlänge des Frames in Millisekunden. Ein LoAF-Eintrag wird nur erstellt, wenn diese 50ms überschreitet. Diese Zahl allein sagt Ihnen, ob der Frame ein Problem darstellt, aber nicht warum.

blockingDuration ist nützlicher. Es summiert die Teile des Frames, die den Long-Task-Schwellenwert überschritten haben, und zieht jeweils 50ms ab. Ein Frame mit duration: 320 und blockingDuration: 0 ist hauptsächlich Rendering-Arbeit. Ein Frame mit duration: 320 und blockingDuration: 270 ist ein langes Script. Das erste erfordert einen Render-Fix. Das zweite erfordert eine Code-Änderung.

renderStart ist der Zeitstempel, an dem der Browser mit der Rendering-Arbeit für den Frame begann. Alles zwischen startTime und renderStart ist Script-Ausführung. Alles danach ist Style, Layout und Paint. Dies ist die nützlichste Grenze für das INP-Debugging, da sie Ihnen sagt, ob der Flaschenhals JavaScript oder Rendering ist.

styleAndLayoutStart ist der Zeitstempel, an dem das Rendering von der Ausführung der Animation-Frame-Callbacks zur tatsächlichen Style-Neuberechnung und zum Layout überging. Die Lücke zwischen renderStart und styleAndLayoutStart sind Ihre requestAnimationFrame-Callbacks. Die Lücke zwischen styleAndLayoutStart und dem Ende des Frames ist browserseitige Style- und Layout-Arbeit.

firstUIEventTimestamp ist der Zeitpunkt, an dem eine Nutzereingabe während des Frames eintraf. Wenn dieser Wert nicht null ist, enthält der Frame eine Interaktion. Auf diese Weise korreliert web-vitals.js LoAF-Einträge mit INP-Messungen. Kein firstUIEventTimestamp bedeutet, dass der Frame langsam ist, aber kein Nutzer darauf gewartet hat.

scripts ist das Array, das Sie für die Attribution lesen. Jeder Eintrag ist ein Script, das für mindestens 5ms gelaufen ist. Es enthält sourceURL, sourceFunctionName, invoker, invokerType, duration und forcedStyleAndLayoutDuration. Das Letzte ist entscheidend: Es sagt Ihnen, ob das Script synchrones Layout ausgelöst hat, was die Hauptursache für die meisten Processing-Time-Engpässe ist, die ich in Audits sehe.

Das Feld invokerType bei jedem Script sagt Ihnen, wie es aufgerufen wurde. Die vollständige Liste ist event-listener (Klicks, Scrolls, Keydowns), user-callback (setTimeout, setInterval, requestAnimationFrame), resolve-promise und reject-promise (Then/Catch-Handler), classic-script und module-script. Für INP lesen Sie zuerst event-listener für Processing Time und user-callback, classic-script oder module-script für Input Delay. Promise-Handler stehen selten ganz oben auf der Liste.

Ordnen Sie diese Felder den drei INP-Phasen zu, und das Bild ist klar. Input Delay zeigt sich als Scripts, die vor firstUIEventTimestamp laufen. Processing Time sind Event-Listener-Scripts, die nach dem UI-Event laufen. Presentation Delay ist alles zwischen renderStart und dem Ende des Frames.

Erfassung von LoAF in Produktion mit web-vitals.js

Sie müssen keinen LoAF-Observer von Grund auf neu erstellen. Der web-vitals.js Attribution-Build erledigt das für Sie und korreliert LoAF-Einträge mit tatsächlichen INP-Messungen. Dies ist die Version, die ich auf Kunden-Websites installiere.

import { onINP } from 'web-vitals/attribution';

onINP((metric) => {
    const a = metric.attribution;

    const payload = {
        value: metric.value,
        rating: metric.rating,
        url: location.pathname,
        loadState: a.loadState,
        interactionTarget: a.interactionTarget,
        interactionType: a.interactionType,
        inputDelay: a.inputDelay,
        processingDuration: a.processingDuration,
        presentationDelay: a.presentationDelay,
        longestScriptDuration: a.longestScript?.entry?.duration,
        longestScriptInvoker: a.longestScript?.entry?.invoker,
        longestScriptSource: a.longestScript?.entry?.sourceURL,
        longestScriptSubpart: a.longestScript?.subpart,
        longestScriptIntersecting: a.longestScript?.intersectingDuration,
    };

    navigator.sendBeacon('/rum', JSON.stringify(payload));
});

Dieser Payload ist klein genug, um ihn ohne Sampling zu senden. Drei Felder übernehmen die meiste Diagnosearbeit: longestScriptInvoker, longestScriptSource und longestScriptSubpart. Die ersten beiden sagen Ihnen, was gelaufen ist. Das dritte sagt Ihnen, in welcher INP-Phase es gelandet ist.

Wenn Sie vollständige Attribution anstelle von nur dem längsten Script möchten, senden Sie auch a.longAnimationFrameEntries. Beachten Sie, dass eine INP-Messung mehrere LoAFs umfassen kann und ein schwerer LoAF zehn oder mehr Script-Einträge enthalten kann. Das Senden des gesamten Arrays bei jedem Seitenaufruf ist teuer. Ich sende das vollständige Array normalerweise nur dann via Beacon, wenn metric.rating !== 'good'.

Ein wichtiges Detail. Das longAnimationFrameEntries-Array ist leer, wenn LoAF und die INP-Kandidaten-Interaktion sich nicht überschneiden oder wenn der Browser LoAF überhaupt nicht unterstützt. Führen Sie immer eine Feature-Erkennung durch, bevor Sie ein leeres Array als sauberes Signal behandeln.

const loafSupported = PerformanceObserver.supportedEntryTypes?.includes('long-animation-frame');

Die Datenschutzaspekte. sourceURL-Werte von Scripts können Query-Parameter und vollständige Pfade enthalten. Für Kundenprojekte entferne ich alles außer Origin und Pathname, bevor ich es an RUM sende. Gehashte Bundle-Dateinamen sind nützlich für das Debugging innerhalb eines Deploys, aber nutzlos für die Gruppierung über Deploys hinweg, also entferne ich auch das Hash-Segment.

Attributionsmuster von 925.000 URLs

CoreDash erfasst die LoAF-Attribution für jede INP-Messung auf den von uns überwachten Websites. In unserem Datensatz von 925.000 URLs taucht immer wieder dieselbe Handvoll von Script-Kategorien als dominante Ursache für blockierende LoAFs auf.

CoreDash dashboard showing LoAF attribution grouped by script origin

Auf E-Commerce-Websites sind die am häufigsten blockierenden Ursprünge konsistent. Tag-Manager, die synchrone benutzerdefinierte HTML-Tags ausführen, stehen an erster Stelle. Consent-Management-Plattformen, die Late-Binding-Script-Injection durchführen, stehen an zweiter Stelle. Die Orchestrierung von Ad- und Bid-Scripts steht an dritter Stelle. Die vierte sind Produktempfehlungs-Widgets, die clientseitig große Mengen hydratisieren. Die fünfte sind Session-Replay-Scripts, die jede Interaktion instrumentieren.

Was Kunden überrascht, ist der Anteil von forcedStyleAndLayoutDuration. Bei einem typischen schlechten INP-Frame machen 30 bis 60% der Dauer des längsten Scripts das Script aus, das synchrones Layout auslöst. Das Script ist nicht langsam, weil das JavaScript schwerfällig ist. Es ist langsam, weil das JavaScript Layout (offsetHeight, getBoundingClientRect) innerhalb einer Schleife liest, die auch in den DOM schreibt. Layout Thrashing. Dasselbe Problem, das Entwickler seit fünfzehn Jahren schreiben, immer noch der größte einzelne Beitrag zur Processing Time auf den Websites, die ich auditiere.

In unserem Datensatz machen event-listener-Invoker etwa die Hälfte der längsten Scripts aus, die sich mit INP überschneiden. user-callback (setTimeout, setInterval, requestAnimationFrame) macht etwa ein Viertel aus. Die Top-Level-Ausführung von classic-script macht den Großteil des Rests aus. Promise-Resolver sind selten das längste Script, was einer gängigen Annahme widerspricht, dass "Async-Code die Ursache" für INP ist.

CoreDash chart showing invokerType distribution for INP-blocking LoAF scripts

Die fünf LoAF-Muster, die ich am häufigsten sehe

Der Third-Party Event-Listener

Das längste Script hat invokerType: "event-listener" und eine sourceURL von einem Third-Party-Ursprung. Die Script-Dauer ist der größte Teil des Frames und forcedStyleAndLayoutDuration ist niedrig. Dies ist ein Vendor-Tag, das auf Ihre Klicks lauscht und zu viel Arbeit im Handler erledigt. Die Lösung lautet selten "Entfernen Sie das Tag." Die Lösung besteht darin, die Arbeit, die das Tag verrichtet, aufzuschieben. Speziell für dataLayer-Pushes gibt es ein Muster, das Ihnen 20 bis 100ms zurückgibt, ohne Analytics zu unterbrechen, was ich in dataLayer-Events planen, um den INP zu optimieren behandelt habe.

Layout Thrashing innerhalb Ihres eigenen Handlers

Das längste Script hat invokerType: "event-listener", die sourceURL ist Ihr eigenes Bundle und forcedStyleAndLayoutDuration beträgt mehr als 30% der Script-Dauer. Das Script liest das Layout in einer Schleife. Die Lösung besteht darin, Lesezugriffe vor Schreibzugriffen zu bündeln oder die Arbeit nach requestAnimationFrame zu verschieben und zwischengespeicherte Werte zu verwenden.

Ich sehe dies am häufigsten auf Produktfilterseiten auf E-Commerce-Websites. Der Filter-Handler aktualisiert die sichtbare Produktanzahl, liest dann die neue Höhe der Ergebnisliste, um einen Sticky-Filter-Button neu zu positionieren, aktualisiert dann eine CSS Custom Property basierend auf dieser Höhe und liest dann die Höhe erneut. Vier erzwungene Layouts in einem Handler. LoAF legt diese 80 bis 150ms von forcedStyleAndLayoutDuration auf einen einzigen Script-Eintrag, und der Fix wird offensichtlich. Einmal lesen, einmal schreiben, beenden.

Hydration-Kaskade bei der ersten Interaktion

Der LoAF feuert, während loadState noch "loading" oder "dom-interactive" ist. firstUIEventTimestamp befindet sich in einem Frame, in dem scripts Framework-Hydration-Callbacks enthält. Der Nutzer hat geklickt, bevor die Seite hydratisiert war. Die Lösung besteht nicht darin, die Hydration schneller zu machen, obwohl das hilft. Die Lösung besteht darin, dass die interaktiven Elemente auch ohne Hydration funktionieren: native Links und Form-Submits, native Disclosure-Widgets, native Dialoge. Progressive Enhancement.

Presentation Delay durch ein schwerfälliges DOM

Dieses Muster sieht in den Daten anders aus. blockingDuration ist niedrig. Das scripts-Array ist kurz. Aber die Lücke zwischen styleAndLayoutStart und dem Ende des Frames beträgt mehr als 100ms. Kein JavaScript-Fix wird helfen. Der Renderer erstickt an der Style-Neuberechnung über Tausende von Nodes hinweg. Verwenden Sie content-visibility: auto für Offscreen-Bereiche, contain: layout style für schwere Komponenten und reduzieren Sie die Größe des Style-Scopes, der pro Interaktion neu berechnet werden muss.

Der rAF-Sturm

Mehrere LoAFs verketten sich, jeder mit einem user-callback-Script, das durch Window.requestAnimationFrame aufgerufen wird. Auf der Seite läuft eine JavaScript-Animation, die mit dem Nutzer konkurriert. JavaScript-gesteuertes Scroll-Verhalten ist die häufigste Variante. Ich habe Websites gesehen, die bei jedem Klick auf jeder Seite 200ms Presentation Delay hinzugefügt haben, wegen eines Smooth-Scroll-Polyfills, an das sich niemand erinnert, es implementiert zu haben. Ich habe den Scroll-Fall in Verbessern Sie den INP durch Verzicht auf JavaScript-Scrolling behandelt. Die gleiche Logik gilt für jede JavaScript-Animation: Wechseln Sie zu CSS oder der Web Animations API und die LoAFs verschwinden.

Wie ein LoAF-Payload in der Praxis aussieht

Hier ist ein echter LoAF-Eintrag aus einem Checkout-Seiten-Audit. Ich habe die URLs anonymisiert, aber die Struktur und Timings sind intakt.

{
    "name": "long-animation-frame",
    "entryType": "long-animation-frame",
    "startTime": 5902,
    "duration": 320,
    "blockingDuration": 268,
    "renderStart": 6170,
    "styleAndLayoutStart": 6172,
    "firstUIEventTimestamp": 5913,
    "scripts": [
        {
            "name": "script",
            "entryType": "script",
            "invoker": "BUTTON#checkout-submit.onclick",
            "invokerType": "event-listener",
            "sourceURL": "https://cdn.example.com/app.HASH.js",
            "sourceFunctionName": "handleCheckoutSubmit",
            "duration": 248,
            "forcedStyleAndLayoutDuration": 142,
            "executionStart": 5914,
            "startTime": 5914
        }
    ]
}

Lesen Sie es so: Der Frame startete bei 5902ms nach dem Laden der Seite. Bei 5913ms klickte der Nutzer auf den Checkout-Submit-Button. Der Click-Handler startete bei 5914ms und lief für 248ms. Von diesen 248ms waren 142ms erzwungenes synchrones Layout. Der Renderer konnte erst bei 6170ms starten, mehr als eine Viertelsekunde nach dem Klick. Der INP für diese Interaktion liegt bei etwa 270ms, im Bereich "needs improvement" ("Verbesserung erforderlich").

Die Lösung lautet nicht "machen Sie handleCheckoutSubmit schneller." Die Lösung lautet "hören Sie auf, das Layout in handleCheckoutSubmit zu erzwingen." 142ms von 248ms sind nicht das JavaScript. Es ist das Lesen von Layout-Werten, die die JavaScript-Schreibvorgänge ungültig gemacht haben. Bei dem echten Fall, aus dem dies stammt, reduzierte das einmalige Zwischenspeichern der gelesenen Werte vor der Schreibschleife die Script-Dauer von 248ms auf 110ms. Der INP auf der Checkout-Seite verbesserte sich von p75 270ms auf unter 200ms. Die Seite hat bestanden.

Das ist die Art von Fix, die in keinem Labor-Tool (Lab Tool) auftaucht. Lighthouse kann Ihnen nichts über forcedStyleAndLayoutDuration sagen, weil Lighthouse nicht mit der Seite interagiert. LoAF in der Praxis ist der einzige Weg, es zu sehen.

DevTools Console output showing the LoAF summary table printed by the webperf-snippets script

Einen KI-Agenten mit LoAF-Daten steuern

Der Grund, warum LoAF für KI-gestütztes Debugging wichtig ist, liegt darin, dass es einem Agenten etwas Konkretes zum Argumentieren gibt. Ein Agent ohne Felddaten (Field Data) kann anhand Ihres Codes über INP-Ursachen spekulieren. Ein Agent mit LoAF-Einträgen aus echten Nutzersitzungen kann das Script, die Funktion und die Phase benennen. Die Diagnose ist keine Vermutung mehr.

Der Workflow, den ich mit Claude Code verwende: Ich ziehe die schlechteste INP-Seite aus CoreDash über den MCP-Server, hänge die LoAF-Einträge für die langsamsten Interaktionen dieser URL an und bitte den Agenten zu identifizieren, welchem der fünf obigen Muster jeder Eintrag entspricht. Der Agent klassifiziert jeden LoAF, verweist auf die Funktion in der Codebasis und schlägt einen Fix vor. Ich überprüfe den Fix. Ich wende ihn an. CoreDash misst, ob sich der p75 INP bewegt.

Das funktioniert, weil LoAF-Daten strukturiert und klein sind. Ein einzelner LoAF-JSON-Payload passt in einen Bruchteil des Kontextfensters eines Agenten. Eine Handvoll repräsentativer LoAFs für eine einzelne Seite reicht aus, um einen Fix zu steuern. Ich habe über das breitere Muster in Beheben Sie INP mit einem KI-Agenten: die Metrik, die Labortools nicht messen können und KI-Agent Core Web Vitals: warum Felddaten alles verändern geschrieben.

Cross-Browser-Realität

LoAF ist exklusiv für Chromium. Safari implementiert es nicht. Firefox implementiert es nicht. Da INP selbst nun in Safari 26.2 und Firefox 144 ausgeliefert wird, haben Sie eine Messlücke. Ihre INP-RUM-Daten gelten browserübergreifend. Ihre Attributionsdaten stammen von Chrome und Edge.

Ich sehe, dass Kunden aus diesem Grund zögern, LoAF einzuführen. Sie wollen warten, bis Safari es veröffentlicht. Das ist die falsche Entscheidung. Chrome ist der Ort, an dem die meisten Performance-Bugs zuerst reproduziert und die meisten Performance-Fixes zuerst validiert werden. Das Muster des Problems (langer Event-Handler, Layout Thrashing, Hydration-Kaskade) ändert sich zwischen Browsern nicht. Nur die diagnostische Linse unterscheidet sich. Fixes, die Sie basierend auf Chromium-LoAF-Daten ausliefern, verbessern den INP auch für Nutzer von Safari und Firefox.

Wenn Sie heute eine Art von Attribution in Safari möchten, ist EventTiming das, was Ihnen zur Verfügung steht. Es sagt Ihnen, welches Event langsam war, aber nicht welches Script. Das reicht aus, um zu wissen, wo Sie suchen müssen, aber nicht, was Sie fixen müssen. Für die Safari-Attribution ist das Lab-Profiling im Safari Web Inspector der praktische Fallback.

Was LoAF Ihnen immer noch nicht sagen kann

Es ist gut, drei blinde Flecken zu kennen, denn sie werden Sie irgendwann überraschen.

Der erste sind Cross-Origin-iFrames. LoAF attribuiert nur Scripts, die auf dem Main Thread von Fenstern laufen, die denselben Ursprung (Origin) wie das Dokument haben. Ein blockierendes Script innerhalb eines Third-Party-iFrames wird als undurchsichtige Attribution angezeigt: ein langer Frame und ein leeres scripts-Array. Die Lösung ist die gleiche wie bei jedem Performance-Problem mit Third-Party-iFrames: Verzögern Sie das Laden des iFrames, geben Sie ihm explizite Dimensionen und verwenden Sie loading="lazy", wenn es Below the Fold liegt.

Worker sind der zweite blinde Fleck. Web-Worker tauchen nicht in LoAF-Einträgen auf, da LoAF eine Main-Thread-API ist. Wenn Ihr INP schlecht ist, weil ein Worker schwere Nachrichten an den Main Thread zurücksendet, zeigt Ihnen LoAF den Message-Handler auf dem Main Thread, aber nicht die Arbeit im Worker, die ihn ausgelöst hat. Sie müssen dies manuell mithilfe von Performance-Marks innerhalb des Workers abgleichen.

Und schließlich das GPU Compositor Delay. Das Ende eines LoAF-Eintrags ist der Zeitpunkt, an dem der Renderer seine Arbeit auf dem Main Thread beendet. Der tatsächliche Pixels-on-Screen-Moment liegt später, im Compositor und in der GPU. Auf Low-End-Android-Geräten kann das Compositor Delay 30 bis 100ms hinzufügen, die LoAF nicht sieht. Das presentationTime-Feld in LoAF-Einträgen (derzeit hinter dem experimentellen PaintTimingMixin-Flag) soll dies adressieren, ist aber noch nicht über alle Chrome-Versionen hinweg stabil.

Nichts davon ist fatal. Es bedeutet nur, dass LoAF nicht die ganze Wahrheit ist. Für 80% der INP-Probleme auf echten Kunden-Websites reicht es völlig aus.

Wo Sie anfangen sollten

Wenn Sie sich noch nie LoAF-Daten angesehen haben, beginnen Sie in der Praxis (im Field), nicht im Labor (Lab). Installieren Sie den web-vitals.js Attribution-Build, senden Sie das längste Script pro INP-Messung via Beacon und schauen Sie sich die Top-Ten der longestScriptSource-Werte über eine Woche Traffic hinweg an. Was auch immer ganz oben steht, ist Ihr erster Fix, unabhängig davon, was Ihr Lighthouse-Report Ihnen sagt.

Wenn Sie die Laboransicht wünschen: Das Performance-Panel der Chrome DevTools zeigt LoAF nicht nativ an, aber die Daten sind über den PerformanceObserver verfügbar. Der Custom-Track-Ansatz, der performance.measure mit dem devtools-Detailfeld verwendet, macht LoAF-Einträge im Panel sichtbar. Das webperf-snippets-Projekt enthält ein Konsolen-Snippet, das eine Übersichtstabelle von LoAF-Einträgen mit Interaktionen druckt. Das ist das, was ich normalerweise als Erstes ausführe, wenn ich eine bestimmte Seite debugge.

Entdecken Sie den Rest der INP-Serie

Das LoAF-Playbook fügt sich in den größeren Workflow ein. Um bei jeder Phase oder jedem Schritt in die Tiefe zu gehen:

Quellen: Chrome for Developers, Long Animation Frames API, MDN, Long animation frame timing, W3C Long Animation Frames specification, GoogleChrome/web-vitals library.

About the author

Arjen Karel is a web performance consultant and the creator of CoreDash, a Real User Monitoring platform that tracks Core Web Vitals data across hundreds of sites. He also built the Core Web Vitals Visualizer Chrome extension. He has helped clients achieve passing Core Web Vitals scores on over 925,000 mobile URLs.

CoreDash hab ich für meine eigenen Audits gebaut.

Unter 1KB. In der EU gehostet. Kein Cookie-Banner. Jetzt mit MCP.

CoreDash kostenlos testen

Ihre Fragen zur Long Animation Frames API beantwortet

Browser-Support und was LoAF ersetzt

Wird die Long Animation Frames API in allen Browsern unterstützt?

Nein. LoAF ist exklusiv für Chromium. Chrome, Edge, Opera und Brave unterstützen es. Safari und Firefox nicht. Führen Sie immer eine Feature-Erkennung mit PerformanceObserver.supportedEntryTypes?.includes('long-animation-frame') durch, bevor Sie sich darauf verlassen.

Ersetzt LoAF die Long Tasks API?

Für das INP-Debugging, ja. Long Tasks liefert Ihnen die Blockierungsdauer auf dem Main Thread ohne Script-Attribution. LoAF liefert Ihnen dasselbe Blockierungssignal plus das tatsächliche Script, das ausgeführt wurde. Es gibt keinen Grund, Long Tasks für neue INP-Arbeiten zu verwenden. Die Total Blocking Time könnte eventuell in Bezug auf die blockingDuration von LoAF neu definiert werden.

LoAF-Daten lesen

Wie korreliere ich einen LoAF-Eintrag mit einer bestimmten INP-Messung?

Der web-vitals.js Attribution-Build erledigt das für Sie über attribution.longAnimationFrameEntries. Er findet die LoAF-Einträge, deren Zeitfenster sich mit der INP-Kandidaten-Interaktion überschneiden. Wenn Sie einen eigenen Observer erstellen, vergleichen Sie entry.startTime und entry.startTime + entry.duration mit der Interaktionszeit und schließen Sie jeden LoAF ein, dessen Fenster sich überschneidet.

Was bedeutet forcedStyleAndLayoutDuration eigentlich?

Es ist die Zeit, die das Script damit verbracht hat, ein synchrones Layout auszulösen. Wenn Ihr JavaScript offsetHeight, getBoundingClientRect oder eine andere Eigenschaft liest, die nach einer DOM-Mutation ein aktuelles Layout erfordert, muss der Browser die Layout-Arbeit synchron innerhalb des Scripts durchführen. Diese Arbeit wird dem Script zugeschrieben. Eine hohe forcedStyleAndLayoutDuration ist fast immer Layout Thrashing.

Warum ist das scripts-Array bei einigen LoAF-Einträgen leer?

Drei Gründe. Erstens enthält der Eintrag nur Scripts, die für mindestens 5ms liefen. Ein Frame voller kurzer Scripts unterhalb dieses Schwellenwerts zeigt keine Attribution. Zweitens werden Scripts, die in Cross-Origin-iFrames, Web-Workern, Service-Workern oder Browser-Erweiterungen laufen, nicht attribuiert, da LoAF nur den Main Thread desselben Ursprungs (Same-Origin) sieht. Drittens enthält der Frame möglicherweise gar keine Script-Arbeit, sondern nur Style und Layout, was dann ein Presentation-Delay-Frame ist.

Über INP hinaus

Kann LoAF bei LCP helfen, nicht nur bei INP?

Ja, indirekt. Ein LoAF, der läuft, bevor das LCP-Element gerendert wird, ist ein langes Script, das den LCP-Render verzögert. Filtern Sie die LoAFs nach denjenigen, deren Endzeit vor dem LCP-Zeitstempel liegt, und das längste Script dort ist der größte Faktor für das LCP-Render-Delay. Dieselben Attributionsdaten, angewendet auf eine andere Metrik.