API voor lange animatieframes

De Long Animation Frames API (LoAF-uitgesproken als Lo-Af) is een update van de Long Tasks API om een ​​beter begrip te bieden van langzame updates van de gebruikersinterface (UI). Dit kan handig zijn om langzame animatieframes te identificeren die waarschijnlijk van invloed zijn op de Interaction to Next Paint (INP) Core Web Vital-metriek die de responsiviteit meet, of om andere UI-janks te identificeren die de vloeiendheid beïnvloeden.

Status van de API

Browserondersteuning

  • Chroom: 123.
  • Rand: 123.
  • Firefox: niet ondersteund.
  • Safari: niet ondersteund.

Bron

Na een origin-proefversie van Chrome 116 naar Chrome 122 is de LoAF API verscheept vanuit Chrome 123 .

Achtergrond: de Lange Taken API

Browserondersteuning

  • Chroom: 58.
  • Rand: 79.
  • Firefox: niet ondersteund.
  • Safari: niet ondersteund.

Bron

De Long Animation Frames API is een alternatief voor de Long Tasks API die al enige tijd beschikbaar is in Chrome (sinds Chrome 58). Zoals de naam al doet vermoeden, kunt u met de Long Task API toezicht houden op lange taken, dit zijn taken die de hoofdreeks 50 milliseconden of langer in beslag nemen. Lange taken kunnen worden gemonitord met behulp van de PerformanceLongTaskTiming -interface, met een PeformanceObserver :

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

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

Lange taken veroorzaken waarschijnlijk reactieproblemen. Als een gebruiker probeert te communiceren met een pagina (bijvoorbeeld door op een knop te klikken of een menu te openen) maar de hoofdthread al bezig is met een lange taak, wordt de interactie van de gebruiker uitgesteld totdat die taak is voltooid.

Om het reactievermogen te verbeteren, wordt vaak geadviseerd om lange taken op te splitsen . Als elke lange taak in plaats daarvan wordt opgedeeld in een reeks van meerdere, kleinere taken, kan het mogelijk zijn dat belangrijkere taken tussendoor worden uitgevoerd om aanzienlijke vertragingen bij het reageren op interacties te voorkomen.

Wanneer we de responsiviteit proberen te verbeteren, bestaat de eerste poging dus vaak uit het uitvoeren van een prestatietracering en het bekijken van lange taken. Dit kan via een laboratoriumgebaseerde audittool zoals Lighthouse (die een audit voor lange hoofdthreadtaken heeft), of door naar lange taken te kijken in Chrome DevTools .

Testen in een laboratorium is vaak een slecht startpunt voor het identificeren van problemen met het reactievermogen , omdat deze tools mogelijk geen interacties omvatten; als ze dat wel doen, vormen ze slechts een kleine subset van waarschijnlijke interacties. Idealiter meet je de oorzaken van langzame interacties in het veld.

Tekortkomingen van de Long Tasks API

Het meten van lange taken in het veld met behulp van een Performance Observer is slechts enigszins nuttig. In werkelijkheid geeft het niet zoveel informatie behalve het feit dat er een lange taak heeft plaatsgevonden en hoe lang deze heeft geduurd.

Real User Monitoring (RUM)-tools gebruiken dit vaak om het aantal of de duur van lange taken te bepalen of om te identificeren op welke pagina's ze plaatsvinden, maar zonder de onderliggende details van wat de lange taak veroorzaakte, is dit slechts van beperkt nut. De Long Tasks API heeft alleen een basisattributiemodel , dat u in het beste geval alleen vertelt in welke container de lange taak plaatsvond (het document op het hoogste niveau of een <iframe> ), maar niet het script of de functie die de taak heeft aangeroepen, zoals blijkt uit een typische invoer:

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

De Long Tasks API is ook een onvolledige weergave, omdat deze ook enkele belangrijke taken kan uitsluiten. Sommige updates, zoals het renderen, vinden plaats in afzonderlijke taken die idealiter samen met de voorgaande uitvoering zouden moeten worden opgenomen, waardoor die update het 'totale werk' voor die interactie nauwkeurig meet. Voor meer details over de beperkingen van het vertrouwen op taken, zie de sectie 'Waar lange taken tekortschieten' van de uitleg .

Het laatste probleem is dat het meten van lange taken alleen rapporteert over individuele taken die langer duren dan de limiet van 50 milliseconden. Een animatieframe kan bestaan ​​uit verschillende taken die kleiner zijn dan deze limiet van 50 milliseconden, maar toch gezamenlijk het weergavevermogen van de browser blokkeren.

De API voor lange animatieframes

Browserondersteuning

  • Chroom: 123.
  • Rand: 123.
  • Firefox: niet ondersteund.
  • Safari: niet ondersteund.

Bron

De Long Animation Frames API (LoAF) is een nieuwe API die een aantal tekortkomingen van de Long Tasks API probeert aan te pakken, zodat ontwikkelaars meer bruikbare inzichten kunnen krijgen om responsiviteitsproblemen aan te pakken en INP te verbeteren, en om inzicht te krijgen in problemen met soepelheid .

Een goede responsiviteit betekent dat een pagina snel reageert op interacties die ermee plaatsvinden. Dat houdt in dat we alle updates die de gebruiker nodig heeft, tijdig kunnen schilderen en kunnen voorkomen dat deze updates worden geblokkeerd. Voor INP wordt aanbevolen om binnen 200 milliseconden of minder te reageren , maar voor andere updates (bijvoorbeeld animaties) kan zelfs 200 milliseconden te lang zijn.

De Long Animation Frames API is een alternatieve benadering voor het meten van blokkeringswerk. In plaats van de afzonderlijke taken te meten, meet de Long Animation Frames API, zoals de naam al doet vermoeden, lange animatieframes . Er is sprake van een lang animatieframe wanneer een weergave-update meer dan 50 milliseconden wordt vertraagd (hetzelfde als de drempelwaarde voor de Long Tasks API).

Lange animatieframes worden gemeten vanaf het begin van taken waarvoor een weergave vereist is. Wanneer de eerste taak in een potentieel lang animatieframe geen render vereist, wordt het lange animatieframe beëindigd na voltooiing van de niet-renderingtaak en wordt een nieuw potentieel lang animatieframe gestart met de volgende taak. Dergelijke niet-renderende lange animatieframes zijn nog steeds opgenomen in de Long Animation Frames API wanneer ze groter zijn dan 50 milliseconden (met een renderStart tijd van 0) om het meten van mogelijk blokkerend werk mogelijk te maken.

Lange animatieframes kunnen op dezelfde manier worden waargenomen als lange taken met een PerformanceObserver , maar in plaats daarvan kijken we naar het type long-animation-frame :

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

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

Eerdere lange animatieframes kunnen ook als volgt uit de prestatietijdlijn worden opgevraagd:

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

Er is echter een maxBufferSize voor prestatiegegevens, waarna nieuwere gegevens worden verwijderd, dus de PerformanceObserver-aanpak is de aanbevolen aanpak. De buffergrootte long-animation-frame is ingesteld op 200, hetzelfde als voor long-tasks .

Voordelen van het kijken naar frames in plaats van naar taken

Het belangrijkste voordeel van het bekijken hiervan vanuit een frameperspectief in plaats van vanuit een taakperspectief, is dat een lange animatie kan bestaan ​​uit een willekeurig aantal taken die cumulatief hebben geresulteerd in een lang animatieframe. Dit betreft het laatste punt dat eerder werd genoemd, waarbij de som van vele kleinere, render-blokkerende taken vóór een animatieframe mogelijk niet naar boven komt door de Long Tasks API.

Een bijkomend voordeel van deze alternatieve kijk op lange taken is de mogelijkheid om timing-uitsplitsingen van het hele frame te bieden. In plaats van alleen een startTime en een duration op te nemen, zoals de Long Tasks API, bevat LoAF een veel gedetailleerder overzicht van de verschillende delen van de frameduur.

Tijdstempels en duur van frames

  • startTime : de starttijd van het lange animatieframe ten opzichte van de starttijd van de navigatie.
  • duration : de duur van het lange animatieframe (exclusief presentatietijd).
  • renderStart : de starttijd van de weergavecyclus, inclusief callbacks requestAnimationFrame , stijl- en lay-outberekening, waarnemer van formaat wijzigen en callbacks van intersectiewaarnemers.
  • styleAndLayoutStart : het begin van de tijdsperiode besteed aan stijl- en lay-outberekeningen.
  • firstUIEventTimestamp : de tijd van de eerste UI-gebeurtenis (muis/toetsenbord enzovoort) die in de loop van dit frame moet worden afgehandeld.
  • blockingDuration : de totale duur in milliseconden waarvoor het animatieframe de verwerking van invoer of andere taken met hoge prioriteit blokkeert.

Een uitleg van blockingDuration

Een lang animatieframe kan uit een aantal taken bestaan. De blockingDuration is de som van de taakduur langer dan 50 milliseconden (inclusief de uiteindelijke weergaveduur binnen de langste taak).

Als een lang animatieframe bijvoorbeeld bestaat uit twee taken van 55 milliseconden en 65 milliseconden gevolgd door een weergave van 20 milliseconden, dan zou de duration ongeveer 140 milliseconden zijn met een blockingDuration van (55 - 50) + (65 + 20 - 50) = 40 milliseconden. Gedurende 40 milliseconden tijdens dit 140 milliseconden lange animatieframe werd het frame beschouwd als geblokkeerd voor het verwerken van invoer.

Of je nu naar duration of blockingDuration kijkt

Voor de gewone 60 hertz-weergave probeert een browser ten minste elke 16,66 milliseconden een frame te plannen (om soepele updates te garanderen), of na een taak met hoge prioriteit, zoals invoerafhandeling (om responsieve updates te garanderen). Als er echter geen invoer is (noch andere taken met hoge prioriteit), maar er is wel een wachtrij met andere taken, zal de browser het huidige frame doorgaans ruim na 16,66 milliseconden voortzetten, ongeacht hoe goed de taken erin zijn opgedeeld. Dat wil zeggen dat de browser altijd zal proberen prioriteit te geven aan invoer, maar ervoor kan kiezen een wachtrij met taken aan te pakken in plaats van render-updates. Dit komt doordat renderen een duur proces is. Het verwerken van een gecombineerde renderingtaak voor meerdere taken leidt doorgaans tot een algehele werkvermindering.

Daarom moeten lange animatieframes met een lage of geen blockingDuration nog steeds reageren op invoer. Het verminderen of elimineren blockingDuration door lange taken op te splitsen is daarom de sleutel tot het verbeteren van de responsiviteit, zoals gemeten door INP.

Veel lange animatieframes geven echter, ongeacht blockingDuration , aan dat UI-updates vertraagd zijn en dus nog steeds de vloeiendheid kunnen beïnvloeden en kunnen leiden tot een gevoel van een trage gebruikersinterface voor scrollen of animaties, ook al zijn deze minder een probleem voor de responsiviteit gemeten door INP. Om problemen op dit gebied te begrijpen, moet u naar de duration kijken, maar deze kunnen lastiger te optimaliseren zijn, omdat u dit niet kunt oplossen door het werk op te splitsen, maar in plaats daarvan het werk moet verminderen.

Frametimings

Met de eerder genoemde tijdstempels kan het lange animatieframe in timings worden verdeeld:

Tijdstip Berekening
Begintijd startTime
Eindtijd startTime + duration
Werkduur renderStart ? renderStart - startTime : duration
Renderduur renderStart ? (startTime + duration) - renderStart: 0
Render: duur vóór de lay-out styleAndLayoutStart ? styleAndLayoutStart - renderStart : 0
Render: duur van stijl en lay-out styleAndLayoutStart ? (startTime + duration) - styleAndLayoutStart : 0

Betere scripttoeschrijving

Het invoertype long-animation-frame bevat betere attributiegegevens van elk script dat heeft bijgedragen aan een lang animatieframe (voor scripts die langer dan 5 milliseconden duren).

Net als bij de Long Tasks API wordt dit aangeboden in een reeks attributie-items, waarvan elk de volgende details bevat:

  • Een name en EntryType retourneren beide script .
  • Een betekenisvolle invoker , die aangeeft hoe het script is aangeroepen (bijvoorbeeld 'IMG#id.onload' , 'Window.requestAnimationFrame' of 'Response.json.then' ).
  • Het invokerType van het scriptingangspunt:
    • user-callback : Een bekende callback die is geregistreerd via een webplatform-API (bijvoorbeeld setTimeout , requestAnimationFrame ).
    • event-listener : Een luisteraar naar een platformgebeurtenis (bijvoorbeeld click , load , keyup ).
    • resolve-promise : Handler van een platformbelofte (bijvoorbeeld fetch() . Merk op dat in het geval van beloften alle handlers van dezelfde beloften samen worden gemengd als één "script") .
    • reject-promise : Volgens resolve-promise , maar voor de afwijzing.
    • classic-script : Scriptevaluatie (bijvoorbeeld <script> of import() )
    • module-script : Hetzelfde als classic-script , maar voor modulescripts.
  • Afzonderlijke timinggegevens voor dat script:
    • startTime : Tijd waarop de invoerfunctie werd aangeroepen.
    • duration : De duur tussen startTime en het moment waarop de daaropvolgende microtaakwachtrij klaar is met verwerken.
    • executionStart : De tijd na het compileren.
    • forcedStyleAndLayoutDuration : De totale tijd die is besteed aan het verwerken van de geforceerde lay-out en stijl binnen deze functie (zie thrashing ).
    • pauseDuration : de totale tijd die is besteed aan het "pauzeren" van synchrone bewerkingen (waarschuwing, synchrone XHR).
  • Details van de scriptbron:
    • sourceURL : De naam van de scriptbron, indien beschikbaar (of leeg als deze niet wordt gevonden).
    • sourceFunctionName : De naam van de scriptfunctie, indien beschikbaar (of leeg als deze niet wordt gevonden).
    • sourceCharPosition : De positie van het scriptteken, indien beschikbaar (of -1 indien niet gevonden).
  • windowAttribution : De container (het document op het hoogste niveau, of een <iframe> ) waarin het lange animatieframe plaatsvond.
  • window : Een verwijzing naar hetzelfde venster.

Waar beschikbaar, kunnen ontwikkelaars dankzij de bronvermeldingen precies weten hoe elk script in het lange animatieframe is aangeroepen, tot aan de tekenpositie in het aanroepende script. Dit geeft de exacte locatie in een JavaScript-bron die resulteerde in het lange animatieframe.

Voorbeeld van een prestatie long-animation-frame

Een compleet voorbeeld van een prestatie-invoer long-animation-frame , dat één enkel script bevat, is:

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

Zoals u kunt zien, levert dit een ongekende hoeveelheid gegevens op voor websites om de oorzaak van laggy rendering-updates te kunnen begrijpen.

Gebruik de Long Animation Frames API in het veld

Tools als Chrome DevTools en Lighthouse zijn, hoewel nuttig voor het ontdekken en reproduceren van problemen, laboratoriumtools die mogelijk belangrijke aspecten van de gebruikerservaring missen die alleen veldgegevens kunnen bieden.

De Long Animation Frames API is ontworpen om in het veld te worden gebruikt om belangrijke contextuele gegevens te verzamelen voor gebruikersinteracties die de Long Tasks API niet kon. Dit kan u helpen bij het identificeren en reproduceren van problemen met interactiviteit die u anders misschien niet zou hebben ontdekt.

Functie voor het detecteren van API-ondersteuning voor lange animatieframes

U kunt de volgende code gebruiken om te testen of de API wordt ondersteund:

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

Het meest voor de hand liggende gebruiksscenario voor de Long Animation Frames API is het helpen diagnosticeren en oplossen van problemen met Interaction to Next Paint (INP) , en dat was een van de belangrijkste redenen waarom het Chrome-team deze API heeft ontwikkeld. Een goede INP is de plaats waar op alle interacties wordt gereageerd binnen 200 milliseconden of minder, vanaf de interactie totdat het frame is geverfd, en aangezien de Long Animation Frames API alle frames meet die 50 ms of langer duren, moeten de meeste problematische INP's LoAF-gegevens bevatten om u te helpen bij het diagnosticeren die interacties.

De "INP LoAF" is de LoAF die de INP-interactie omvat, zoals weergegeven in het volgende diagram:

Voorbeelden van lange animatieframes op een pagina, waarbij de INP LoAF is gemarkeerd.
Een pagina kan veel LoAF's hebben, waarvan er één gerelateerd is aan de INP-interactie.

In sommige gevallen is het mogelijk dat een INP-gebeurtenis twee LoAF's omvat, meestal als de interactie plaatsvindt nadat het frame is begonnen met het renderen van een deel van het vorige frame, en dus de gebeurtenishandler wordt verwerkt in het volgende frame:

Voorbeelden van lange animatieframes op een pagina, waarbij de INP LoAF is gemarkeerd.
Een pagina kan veel LoAF's hebben, waarvan er één gerelateerd is aan de INP-interactie.

Het is zelfs mogelijk dat het in zeldzame omstandigheden meer dan twee LoAF's omvat.

Door de LoAF(s)-gegevens te registreren die verband houden met de INP-interactie, kunt u veel meer informatie krijgen over de INP-interactie om deze te helpen diagnosticeren. Dit is vooral handig om de invoervertraging te begrijpen: u kunt zien welke andere scripts in dat frame werden uitgevoerd.

Het kan ook nuttig zijn om de onverklaarbare verwerkingsduur en presentatievertraging te begrijpen als uw gebeurtenishandlers niet de waarden reproduceren die daarvoor worden gezien, omdat er mogelijk andere scripts voor uw gebruikers worden uitgevoerd die mogelijk niet zijn opgenomen in uw eigen tests.

Er is geen directe API om een ​​INP-item te koppelen aan de bijbehorende LoAF-item(s) , hoewel het wel mogelijk is om dit in code te doen door de begin- en eindtijden van elk te vergelijken (zie het WhyNp -voorbeeldscript ). De web-vitals -bibliotheek bevat alle kruisende LoAF's in de eigenschap longAnimationFramesEntries van de INP-attributie-interface vanaf v4.

Nadat u de LoAF-vermelding(en) heeft gekoppeld, kunt u informatie opnemen met INP-toeschrijving. Het scripts object bevat een aantal van de meest waardevolle informatie, omdat het kan laten zien wat er nog meer in die frames draaide. Door die gegevens terug te sturen naar uw analyseservice, kunt u beter begrijpen waarom interacties traag waren.

Het rapporteren van LoAF's voor de INP-interactie is een goede manier om de meest urgente interactiviteitsproblemen op uw pagina te vinden. Elke gebruiker kan op een andere manier met uw pagina omgaan en als er voldoende INP-attributiegegevens zijn, worden er een aantal potentiële problemen opgenomen in de INP-attributiegegevens. Hiermee kunt u scripts op volume sorteren om te zien welke scripts correleren met trage INP.

Rapporteer meer lange animatiegegevens terug naar een analyse-eindpunt

Eén nadeel van alleen kijken naar de INP LoAF(s) is dat je mogelijk andere potentiële gebieden voor verbeteringen mist die toekomstige INP-problemen kunnen veroorzaken. Dit kan leiden tot het gevoel dat je achter je aan zit als je een INP-probleem oplost in de verwachting een enorme verbetering te zien, maar dan ontdekt dat de volgende langzaamste interactie slechts een klein beetje beter is dan dat, zodat je INP niet veel verbetert.

Dus in plaats van alleen naar de INP LoAF te kijken, wil je misschien alle LoAF's gedurende de levensduur van de pagina in overweging nemen:

Een pagina met veel LoAF's, waarvan sommige plaatsvinden tijdens interacties, zelfs als dit niet de INP-interactie is.
Door naar alle LoAF's te kijken, kunnen toekomstige INP-problemen worden geïdentificeerd.

Elke LoAF-vermelding bevat echter een aanzienlijke hoeveelheid gegevens, dus u zult uw analyse waarschijnlijk willen beperken tot slechts enkele LoAF's. Omdat de lange animatieframe-items behoorlijk groot kunnen zijn, moeten ontwikkelaars bovendien beslissen welke gegevens uit het item naar Analytics moeten worden gestuurd. Bijvoorbeeld de samenvattingstijden van de invoer en misschien de scriptnamen, of een andere minimale reeks andere contextuele gegevens die mogelijk noodzakelijk worden geacht.

Enkele voorgestelde patronen om de hoeveelheid lange animatieframegegevens te verminderen zijn onder meer:

Welke van deze patronen voor u het beste werkt, hangt af van hoe ver u zich op uw optimalisatietraject bevindt en hoe vaak lange animatieframes voorkomen. Voor een site die nog nooit eerder is geoptimaliseerd voor responsiviteit, kunnen er veel LoAF's zijn die u wilt beperken tot alleen LoAF's met interacties, of een hoge drempel wilt instellen, of alleen naar de ergste wilt kijken.

Terwijl u uw veelvoorkomende problemen met het reactievermogen oplost, kunt u dit uitbreiden door u niet te beperken tot alleen interacties of een hoge blokkeringsduur, of door de drempels te verlagen.

Observeer lange animatieframes met interacties

Om meer inzicht te krijgen dan alleen het lange INP-animatieframe, kunt u naar alle LoAF's kijken met interacties (die kunnen worden gedetecteerd door de aanwezigheid van een firstUIEventTimestamp -waarde) met een hoge blockingDuration .

Dit kan ook een eenvoudigere methode zijn om INP LoAF's te monitoren in plaats van te proberen de twee met elkaar in verband te brengen, wat complexer kan zijn. In de meeste gevallen omvat dit de INP LoAF voor een bepaald bezoek, en in zeldzame gevallen waarin dit niet het geval is, komen er nog steeds lange interacties naar voren die belangrijk zijn om op te lossen, omdat dit de INP-interactie voor andere gebruikers kan zijn.

De volgende code registreert alle LoAF-vermeldingen met een blockingDuration groter dan 100 milliseconden waarbij een interactie plaatsvond tijdens het frame. De 100 is hier gekozen omdat deze minder is dan de "goede" INP-drempel van 200 milliseconden. Afhankelijk van uw behoeften kunt u een hogere of lagere waarde kiezen.

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

Observeer lange animatieframes met een hoge blokkeerduur

Als verbetering ten opzichte van het bekijken van alle lange animatieframes met interacties, wilt u wellicht ook naar alle lange animatieframes met een hoge blokkeringsduur kijken. Deze duiden op mogelijke INP-problemen als een gebruiker interactie heeft tijdens deze lange animatieframes.

De volgende code registreert alle LoAF-vermeldingen met een blokkeerduur van meer dan 100 milliseconden waarbij een interactie plaatsvond tijdens het frame. De 100 is hier gekozen omdat deze minder is dan de 'goede' INP-drempel van 200 milliseconden om potentiële probleemframes te helpen identificeren, terwijl het aantal gerapporteerde lange animatieframes tot een minimum wordt beperkt. Afhankelijk van uw behoeften kunt u een hogere of lagere waarde kiezen.

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

Observeer lange animatieframes tijdens kritieke UI-updates om de vloeiendheid te verbeteren

Zoals eerder vermeld, kan het kijken naar lange animatieframes met een hoge blokkeringsduur helpen de responsiviteit van de invoer aan te pakken. Maar voor vloeiendheid moet je kijken naar alle lange animatieframes met een lange duration .

Omdat dit nogal luidruchtig kan zijn, wil je de metingen hiervan misschien beperken tot belangrijke punten met een patroon als dit:

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

Observeer de slechtste lange animatieframes

In plaats van een vaste drempel te hebben, willen sites mogelijk gegevens verzamelen over het langste animatieframe (of frames), om de hoeveelheid gegevens die moet worden beaconed te verminderen. Dus ongeacht hoeveel lange animatieframes een pagina ervaart, worden alleen gegevens van de slechtste, vijf, tien of hoeveel lange animatieframes ook absoluut noodzakelijk zijn, weergegeven.

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

Deze strategieën kunnen ook worden gecombineerd: kijk alleen naar de tien slechtste LoAF's, met interacties langer dan 100 milliseconden.

Op het juiste moment ( idealiter tijdens de visibilitychange ) keert u terug naar analyses. Voor lokaal testen kunt u periodiek console.table gebruiken:

console.table(longestBlockingLoAFs);

Identificeer algemene patronen in lange animatieframes

Een alternatieve strategie zou zijn om te kijken naar veelgebruikte scripts die het meest voorkomen in lange animatieframe-items. Gegevens kunnen worden teruggekoppeld op script- en karakterpositieniveau om recidivisten te identificeren.

Dit kan met name goed werken voor aanpasbare platforms waar thema's of plug-ins die prestatieproblemen veroorzaken op een aantal sites kunnen worden geïdentificeerd.

De uitvoeringstijd van veelgebruikte scripts (of de oorsprong van derden) in lange animatieframes kan worden samengevat en gerapporteerd om gemeenschappelijke bijdragers aan lange animatieframes op een site of een verzameling sites te identificeren. Als u bijvoorbeeld naar URL's wilt kijken:

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

En een voorbeeld van deze uitvoer is:

(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

Gebruik de Long Animation Frames API in tooling

De API maakt ook aanvullende ontwikkelaarstools mogelijk voor lokale foutopsporing. Hoewel sommige tools zoals Lighthouse en Chrome DevTools veel van deze gegevens hebben kunnen verzamelen met behulp van traceringsdetails op een lager niveau, zou het hebben van deze API op een hoger niveau ervoor kunnen zorgen dat andere tools toegang krijgen tot deze gegevens.

Bekijk gegevens over lange animatieframes in DevTools

U kunt lange animatieframes in DevTools weergeven met behulp van de performance.measure() API, die vervolgens worden weergegeven in de DevTools-gebruikerstimingstrack in prestatiesporen om aan te geven waar u zich op moet richten voor prestatieverbeteringen. Met behulp van de DevTools Extensibility API kunnen deze zelfs in hun eigen track worden getoond:

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 Performance Panel-trace met een aangepaste track die Long Animation Frame-gegevens toont die kunnen worden vergeleken met de hoofdvlamgrafiek.
Lange animatieframegegevens weergeven in DevTools.

Op de langere termijn zullen waarschijnlijk lange animatieframes in DevTools zelf worden opgenomen, maar dankzij het vorige codefragment kan het daar in de tussentijd worden weergegeven.

Het eerste item in de vorige afbeelding laat ook zien waar de browser verschillende taken samen in hetzelfde lange animatieframe heeft verwerkt in plaats van ertussen te renderen. Zoals eerder vermeld kan dit gebeuren als er geen invoertaken met hoge prioriteit zijn, maar er wel een wachtrij met taken is. De eerste lange taak moet enkele render-updates voltooien (anders zou het huidige lange animatieframe daarna worden gereset en zou een nieuw frame beginnen met de volgende taak), maar in plaats van onmiddellijk actie te ondernemen die render, heeft de browser een aantal extra taken en voerde daarna pas de lange rendertaak uit en beëindigde het lange animatieframe. Dit demonstreert het nut van het kijken naar lange animatieframes in DevTools, in plaats van alleen naar lange taken, om vertraagde weergaven te helpen identificeren.

Gebruik lange animatieframegegevens in andere ontwikkelaarstools

De Web Vitals-extensie heeft de waarde laten zien van het loggen van samenvattende foutopsporingsinformatie om prestatieproblemen te diagnosticeren.

Er worden nu ook lange animatieframegegevens weergegeven voor elke INP-callback en elke interactie:

Registratie van de Web Vitals Extensieconsole.
Loggen van de Web Vitals Extension-console geeft LoAF-gegevens weer.

Gebruik lange animatieframegegevens in geautomatiseerde testtools

Op vergelijkbare wijze kunnen geautomatiseerde testtools in CI/CD-pijplijnen details over potentiële prestatieproblemen naar boven halen door lange animatieframes te meten terwijl verschillende testsuites worden uitgevoerd.

Veelgestelde vragen

Enkele van de veelgestelde vragen over deze API zijn:

Waarom niet gewoon de Long Tasks API uitbreiden of herhalen?

Dit is een alternatieve kijk op het rapporteren van een vergelijkbare – maar uiteindelijk andere – meting van potentiële problemen met het reactievermogen. Het is belangrijk om ervoor te zorgen dat sites die afhankelijk zijn van de bestaande Long Tasks API blijven functioneren om te voorkomen dat bestaande gebruiksscenario's worden verstoord.

Hoewel de Long Tasks API kan profiteren van enkele kenmerken van LoAF (zoals een beter attributiemodel), zijn wij van mening dat het focussen op frames in plaats van taken veel voordelen biedt die dit een fundamenteel andere API maken dan de bestaande Long Tasks API.

Waarom heb ik geen scriptvermeldingen?

Dit kan erop wijzen dat het lange animatieframe niet te wijten was aan JavaScipt, maar aan het grote renderwerk.

Dit kan ook gebeuren wanneer het lange animatieframe te wijten is aan JavaScript, maar waarbij de scripttoeschrijving om verschillende privacyredenen niet kan worden geleverd, zoals eerder vermeld (voornamelijk omdat JavaScript geen eigendom is van de pagina).

Waarom heb ik scriptvermeldingen maar geen of beperkte broninformatie?

Dit kan verschillende redenen hebben, waaronder het ontbreken van een goede bron om naar te verwijzen .

Scriptinformatie is ook beperkt tot alleen de sourceURL (exclusief eventuele omleidingen) voor no-cors cross-origin , met een lege tekenreeks voor de sourceFunctionName en een -1 voor sourceCharPosition . Dit kan worden opgelost door deze scripts op te halen met behulp van CORS door crossOrigin = "anonymous" toe te voegen aan de <script> -aanroep.

Bijvoorbeeld het standaard Google Tag Manager-script dat aan de pagina moet worden toegevoegd:

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

Kan worden uitgebreid door j.crossOrigin = "anonymous" toe te voegen, zodat volledige attributiegegevens voor GTM kunnen worden verstrekt.

Zal dit de Long Tasks API vervangen?

Hoewel we van mening zijn dat de Long Animation Frames API een betere, completere API is voor het meten van lange taken, zijn er op dit moment geen plannen om de Long Tasks API te beëindigen.

Feedback gewenst

Feedback kan worden gegeven op de GitHub Issues-lijst , of bugs in de Chrome-implementatie van de API kunnen worden opgeslagen in de issue tracker van Chrome .

Conclusie

De Long Animation Frames API is een opwindende nieuwe API met veel potentiële voordelen ten opzichte van de vorige Long Tasks API.

Het blijkt een belangrijk instrument te zijn voor het aanpakken van responsiviteitsproblemen, zoals gemeten door INP. INP is een uitdagende statistiek om te optimaliseren en deze API is een manier waarop het Chrome-team het identificeren en aanpakken van problemen voor ontwikkelaars eenvoudiger wil maken.

De reikwijdte van de Long Animation Frames API reikt echter verder dan alleen INP en kan helpen bij het identificeren van andere oorzaken van trage updates die de algehele soepelheid van de gebruikerservaring van een website kunnen beïnvloeden.

Dankbetuigingen

Miniatuurafbeelding door Henry Be op Unsplash .