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
Na een origin-proefversie van Chrome 116 naar Chrome 122 is de LoAF API verscheept vanuit Chrome 123 .
Achtergrond: de Lange Taken API
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 controleren 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
De Long Animation Frames API (LoAF) is een nieuwe API die een aantal van de 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 callbacksrequestAnimationFrame
, berekening van stijl en lay-out, callbacks van waarnemers van formaat wijzigen en 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 zou bestaan 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: Stijl- en lay-outduur | 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 langer dan 5 milliseconden).
Net als bij de Long Tasks API wordt dit aangeboden in een reeks attributie-items, waarvan elk de volgende details bevat:
- Een
name
enEntryType
retourneren beidescript
. - 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 (bijvoorbeeldsetTimeout
,requestAnimationFrame
). -
event-listener
: Een luisteraar naar een platformgebeurtenis (bijvoorbeeldclick
,load
,keyup
). -
resolve-promise
: Handler van een platformbelofte (bijvoorbeeldfetch()
. Merk op dat in het geval van beloften alle handlers van dezelfde beloften samen worden gemengd als één "script").
-
reject-promise
: Volgensresolve-promise
, maar voor de afwijzing. -
classic-script
: Scriptevaluatie (bijvoorbeeld<script>
ofimport()
) -
module-script
: Hetzelfde alsclassic-script
, maar voor modulescripts.
-
- Afzonderlijke timinggegevens voor dat script:
-
startTime
: Tijd waarop de invoerfunctie werd aangeroepen. -
duration
: De duur tussenstartTime
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 waarmee websites de oorzaak van laggy rendering-updates 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
}
Link naar de langste INP-interactie
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:
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:
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
Een 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:
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:
- Observeer lange animatieframes met interacties
- Observeer lange animatieframes met een hoge blokkeerduur
- Observeer lange animatieframes tijdens kritieke UI-updates om de vloeiendheid te verbeteren
- Observeer de slechtste lange animatieframes
- Identificeer algemene patronen in lange animatieframes
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.
Naarmate 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 kijken naar alle lange animatieframes met interacties, wil je misschien 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 blokkeringsduur 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 van 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 });
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:
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 duiden 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 .
,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
Na een origin-proefversie van Chrome 116 naar Chrome 122 is de LoAF API verscheept vanuit Chrome 123 .
Achtergrond: de Lange Taken API
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 controleren 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 uiteindelijke probleem is dat het meten van lange taken alleen rapporteert over individuele taken die langer duren dan de limiet van 50 milliseconden. Een animatiekader kan bestaan uit verschillende taken die kleiner zijn dan deze limiet van 50 milliseconden, maar blokkeert gezamenlijk nog steeds het vermogen van de browser om te renderen.
De lange animatie frames API
De Long Animation Frames API (LOAF) is een nieuwe API die een deel van de tekortkomingen van de Long Tasks API wil aanpakken om ontwikkelaars in staat te stellen meer bruikbare inzichten te krijgen om de responsiviteitsproblemen aan te pakken en de INP te verbeteren, en inzichten te krijgen in soepelheidsproblemen .
Een goede responsiviteit betekent dat een pagina snel reageert op interacties die ermee zijn gemaakt. Dat houdt in dat u eventuele updates van de gebruiker tijdig kunt schilderen en het voorkomen van het blokkeren van deze updates. Voor INP wordt het aanbevolen om in 200 milliseconden of minder te reageren , maar voor andere updates (bijvoorbeeld animaties) kunnen zelfs 200 milliseconden te lang zijn.
De Long Animation Frames API is een alternatieve benadering voor het meten van blokkeerwerk. In plaats van de individuele taken te meten, frames API - zoals de naam al doet vermoeden - de lange animatiekaders . Een lang animatiekader is wanneer een rendering -update wordt uitgesteld na 50 milliseconden (hetzelfde als de drempel voor de lange taken API).
Lange animatiekaders worden gemeten vanaf het begin van taken die een render vereisen. Waar de eerste taak in een potentieel lang animatiekader geen render vereist, wordt het lange animatiekader beëindigd na voltooiing van de niet-renderingtaak en een nieuw potentieel lang animatiekader wordt gestart met de volgende taak. Een dergelijk niet-renderende lange animatiekader is nog steeds opgenomen in de lange animatiekaders API wanneer groter dan 50 milliseconden (met een renderStart
tijd van 0) om het meten van mogelijk blokkerende werkzaamheden mogelijk te maken.
Lange animatiekaders kunnen op een vergelijkbare manier worden waargenomen als lange taken met een PerformanceObserver
, maar in plaats daarvan kijken naar long-animation-frame
type:
const observer = new PerformanceObserver((list) => {
console.log(list.getEntries());
});
observer.observe({ type: 'long-animation-frame', buffered: true });
Eerdere lange animatiekaders kunnen ook worden opgevraagd uit de tijdlijn van de uitvoering zoals zo:
const loafs = performance.getEntriesByType('long-animation-frame');
Er is echter een maxBufferSize
voor prestatie -inzendingen waarna nieuwere inzendingen worden gedropt, 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 taken
Het belangrijkste voordeel om dit te bekijken vanuit een frame -perspectief in plaats van een takenperspectief, is dat een lange animatie kan bestaan uit een aantal taken die cumulatief resulteerden in een lang animatiekader. Dit behandelt het laatste punt dat eerder werd genoemd, waarbij de som van veel kleinere, render-blokkerende taken vóór een animatiekader mogelijk niet wordt opgedoken door de lange taken API.
Een verder voordeel van deze alternatieve weergave bij lange taken, is de mogelijkheid om timingafbraak van het hele frame te bieden. In plaats van alleen een startTime
en een duration
op te nemen, zoals de lange taken API, bevat Loaf een veel gedetailleerdere afbraak van de verschillende delen van de frameduur.
Frame tijdstempels en duur
-
startTime
: de starttijd van het lange animatiekader ten opzichte van de starttijd van de navigatie. -
duration
: de duur van het lange animatiekader (exclusief presentatietijd). -
renderStart
: de starttijd van de renderingcyclus, dierequestAnimationFrame
callbacks, stijl- en lay -outberekening omvat, de wijziging van de callbacks van de waarnemer en de snijpunt van de kruising waarborgt. -
styleAndLayoutStart
: het begin van de tijdsperiode doorgebracht in stijl- en lay -outberekeningen. -
firstUIEventTimestamp
: De tijd van het eerste UI -evenement (muis/toetsenbord enzovoort) die tijdens dit frame moet worden afgehandeld. -
blockingDuration
: de totale duur in milliseconden waarvoor het animatiekader de verwerking van invoer of andere hoge prioriteitstaken zou blokkeren.
Een uitleg van blockingDuration
Een lang animatiekader kan bestaan uit een aantal taken. De blockingDuration
is de som van taakduur langer dan 50 milliseconden (inclusief de uiteindelijke render -duur binnen de langste taak).
For example, if a long animation frame was made up of two tasks of 55 milliseconds and 65 milliseconds followed by a render of 20 milliseconds, then the duration
would be approximately 140 milliseconds with a blockingDuration
of (55 - 50) + (65 + 20 - 50) = 40 milliseconden. Voor 40 milliseconden tijdens dit 140 millisecond lange animatiekader werd het frame beschouwd als geblokkeerd door de hanteringsinvoer.
Of u nu naar duration
of blockingDuration
moet kijken
Voor het gewone 60 Hertz -display zal een browser proberen een frame te plannen ten minste om de 16,66 milliseconden (om soepele updates te garanderen), of na een taak met een hoge prioriteit zoals invoerafhandeling (om responsieve updates te garanderen). Als er echter geen input is-geen andere taken met hoge prioriteit-maar er is een wachtrij van andere taken, zal de browser doorgaans het huidige frame verder doorgaan ver na 16,66 milliseconden, ongeacht hoe goed de taken erin zitten. Dat wil zeggen, de browser zal altijd proberen prioriteit te geven aan inputs, maar kan ervoor kiezen om een wachtrij van taken aan te pakken ten opzichte van render -updates. Dit komt door het feit dat het een duur proces is, dus het verwerken van een gecombineerde renderingtaak voor meerdere taken leidt meestal tot een algehele vermindering van het werk.
Daarom moeten lange animatiekaders met een lage of nul blockingDuration
nog steeds reageren op invoer. Het verminderen of elimineren blockingDuration
door lange taken op te splitsen, is daarom van cruciaal belang om de responsiviteit te verbeteren zoals gemeten door INP.
Veel lange animatiekaders, ongeacht blockingDuration
duidt echter op UI -updates die zijn vertraagd en kunnen dus nog steeds de gladheid beïnvloeden en leiden tot een gevoel van een laggy gebruikersinterface voor scrollen of animaties, zelfs als dit minder een probleem is voor responsiviteit als gemeten door Inp. Om problemen in dit gebied te begrijpen, kijken naar de duration
, maar deze kunnen lastig zijn om te optimaliseren, omdat u dit niet kunt oplossen door werk te verbreken, maar in plaats daarvan het werk moet verminderen.
Frametimings
Door de eerder genoemde tijdstempels kan het lange animatiekader worden verdeeld in timings:
Tijdstip | Berekening |
---|---|
Starttijd | startTime |
Eindtijd | startTime + duration |
Werkduur | renderStart ? renderStart - startTime : duration |
De duur | renderStart ? (startTime + duration) - renderStart: 0 |
Render: duur voor de layout | styleAndLayoutStart ? styleAndLayoutStart - renderStart : 0 |
Render: stijl en lay -outduur | styleAndLayoutStart ? (startTime + duration) - styleAndLayoutStart : 0 |
Betere script -toeschrijving
Het invoertype long-animation-frame
bevat betere attributiegegevens van elk script die hebben bijgedragen aan een lang animatiekader (voor scripts langer dan 5 milliseconden).
Vergelijkbaar met de Long Taken API, wordt dit verstrekt in een reeks toeschrijving, die elk details:
- Een
name
enEntryType
beiden retourneertscript
. - Een zinvolle
invoker
, die aangeeft hoe het script werd aangeroepen (bijvoorbeeld'IMG#id.onload'
,'Window.requestAnimationFrame'
, of'Response.json.then'
). - De
invokerType
van het scriptinvoerpunt:-
user-callback
: een bekende callback geregistreerd bij een webplatform API (bijvoorbeeldsetTimeout
,requestAnimationFrame
). -
event-listener
: een luisteraar naar een platformgebeurtenis (bijvoorbeeld klik,click
,load
,keyup
). -
resolve-promise
: Handler van een platformbelofte (bijvoorbeeldfetch()
. Merk op dat in het geval van beloften alle handlers van dezelfde beloften samen worden gemengd als één "script").
-
reject-promise
: volgensresolve-promise
, maar voor de afwijzing. -
classic-script
: Script Evaluation (bijvoorbeeld<script>
ofimport()
) -
module-script
: hetzelfde alsclassic-script
, maar voor modulescripts.
-
- Afzonderlijke timinggegevens voor dat script:
-
startTime
: tijd dat de invoerfunctie werd ingeroepen. -
duration
: de duur tussenstartTime
en wanneer de volgende microtask -wachtrij is voltooid. -
executionStart
: de tijd na compilatie. -
forcedStyleAndLayoutDuration
: de totale tijd besteed aan het verwerken van geforceerde lay -out en stijl in deze functie (zie Thrashing ). -
pauseDuration
: totale tijd besteed aan "pauzerende" synchrone bewerkingen (alert, synchrone XHR).
-
- Scriptbron details:
-
sourceURL
: de naam van de scriptbronnen waar beschikbaar (of leeg als niet wordt gevonden). -
sourceFunctionName
: de naam van de scriptfunctie indien beschikbaar (of leeg als niet wordt gevonden). -
sourceCharPosition
: de scripttekenpositie waar beschikbaar (of -1 indien niet gevonden).
-
-
windowAttribution
: de container (het document op het hoogste niveau of een<iframe>
) het lange animatiekader vond plaats. -
window
: een verwijzing naar hetzelfde venster met hetzelfde origin.
Waar aangeboden, kunnen de bronitems ontwikkelaars precies weten hoe elk script in het lange animatiekader werd opgeroepen, tot de tekenpositie in het oproepende script. Dit geeft de exacte locatie in een JavaScript -bron die resulteerde in het lange animatiekader.
Voorbeeld van een long-animation-frame
inzending
Een compleet voorbeeld van long-animation-frame
, met een enkel script, 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 te zien is, geeft dit een ongekende hoeveelheid gegevens voor websites om de oorzaak van laggy -rendering -updates te kunnen begrijpen.
Gebruik de lange animatiekaders API in het veld
Tools zoals Chrome Devtools en Lighthouse - terwijl nuttig is voor het ontdekken en reproduceren van problemen - zijn laboratoriumtools die belangrijke aspecten van de gebruikerservaring kunnen 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 lange taken API niet konden. Dit kan u helpen om problemen te identificeren en te reproduceren met interactiviteit die u anders misschien niet hebt ontdekt.
Feature Detecting Long Animation Frames API -ondersteuning
U kunt de volgende code gebruiken om te testen of de API wordt ondersteund:
if (PerformanceObserver.supportedEntryTypes.includes('long-animation-frame')) {
// Monitor LoAFs
}
Link naar de langste INP -interactie
De meest voor de hand liggende use case voor de lange animatiekaders API is om interactie te diagnosticeren en op te lossen aan de volgende Paint (INP) -problemen, en dat was een van de belangrijkste redenen waarom het Chrome -team deze API heeft ontwikkeld. Een goede INP is waar op alle interacties in 200 milliseconden of minder van interactie wordt gereageerd totdat het frame is geverfd, en aangezien de lange animatiereis API -frames alle frames meet die 50 ms of meer kosten, moeten de meeste problematische inps loafgegevens bevatten om u te helpen diagnosticeren Die interacties.
De "INP Loaf" is het brood dat de INP -interactie omvat, zoals weergegeven in het volgende diagram:
In sommige gevallen is het mogelijk dat een INP -gebeurtenis twee broodjes omvat - typisch als de interactie plaatsvindt nadat het frame het renderinggedeelte van het vorige frame is begonnen, en daarom wordt de gebeurtenishandler in het volgende frame verwerkt:
Het is zelfs mogelijk dat het in sommige zeldzame omstandigheden meer dan twee broodjes kan overspannen.
Door de LOAF (S) -gegevens op te nemen die zijn gekoppeld aan de INP -interactie, kunt u veel meer informatie krijgen over de INP -interactie om deze te helpen diagnosticeren. Dit is met name handig om inputvertraging te begrijpen: omdat u kunt zien wat andere scripts in dat frame liepen.
Het kan ook nuttig zijn om onverklaarbare verwerkingsduur en presentatievertraging te begrijpen als uw gebeurtenishandlers de waarden die worden waargenomen, als andere scripts mogelijk niet voor uw gebruikers reproduceren die mogelijk niet in uw eigen testen worden opgenomen.
Er is geen directe API om een INP -invoer te koppelen aan zijn gerelateerde brooditems of vermeldingen , hoewel het mogelijk is om dit in code te doen door de start- en eindtijden van elk te vergelijken (zie het WHYNP -voorbeeldscript ). De web-vitals
-bibliotheek bevat alle kruisende broodjes in de eigenschap longAnimationFramesEntries
van de Inp Attribution Interface van V4.
Nadat u de brooditem of vermeldingen hebt gekoppeld, kunt u informatie opnemen met INP -toeschrijving. Het scripts
bevat enkele van de meest waardevolle informatie, omdat het kan aantonen wat er nog meer in die frames werd uitgevoerd, zodat het terugbouwen van die gegevens naar uw analyseservice, u meer kunt begrijpen waarom interacties traag waren.
Loafs rapporteren voor de Inp -interactie is een goede manier om te vinden wat de meest dringende interactiviteitsproblemen op uw pagina zijn. Elke gebruiker kan anders communiceren met uw pagina en met voldoende volume inp -toeschrijvinggegevens, worden een aantal potentiële problemen opgenomen in Inp -toeschrijvinggegevens. Hiermee kunt u scripts per volume sorteren om te zien welke scripts correleren met Slow InP.
Meld meer lange animatiegegevens terug naar een analyse -eindpunt
Een nadeel om alleen naar de Inp -brood (s) te kijken, is dat u misschien andere potentiële gebieden mist voor verbeteringen die toekomstige INP -problemen kunnen veroorzaken. Dit kan leiden tot een gevoel van het achtervolgen van je staart waar je een INP -probleem oplost en verwacht een enorme verbetering te zien, alleen om te vinden dat de volgende langzaamste interactie slechts een kleine hoeveelheid beter is dan dat, dus je INP verbetert niet veel.
Dus in plaats van alleen naar het inp -brood te kijken, wilt u misschien alle broodjes tijdens de levenslange lifetime overwegen:
Elk brooditem bevat echter aanzienlijke gegevens, dus u wilt waarschijnlijk uw analyse beperken tot slechts enkele broodjes. Omdat de lange animatiekaderitems vrij groot kunnen zijn, moeten ontwikkelaars beslissen welke gegevens van de invoer naar analyse moeten worden verzonden. Bijvoorbeeld, de samenvattende tijden van de invoer en misschien de scriptnamen, of een andere minimale set andere contextuele gegevens die nodig kunnen worden geacht.
Sommige voorgestelde patronen om de hoeveelheid lange animatiekadergegevens te verminderen, omvatten:
- Observeer lange animatiekaders met interacties
- Observeer lange animatiekaders met hoge blokkerende duur
- Observeer lange animatiekaders tijdens kritieke UI -updates om de soepelheid te verbeteren
- Observeer de ergste lange animatiekaders
- Identificeer gemeenschappelijke patronen in lange animatiekaders
Welke van deze patronen het beste voor u werkt, hangt af van hoe ver u zich bent op uw optimalisatiereis en hoe vaak de lange animatiekaders zijn. Voor een site die nog nooit eerder is geoptimaliseerd voor responsiviteit, kunnen er veel boden zijn, wilt u misschien beperken tot alleen loafs met interacties, of een hoge drempel instellen, of alleen naar de slechtste kijken.
Naarmate u uw gemeenschappelijke responsiviteitsproblemen oplost, kunt u dit uitbreiden door niet te beperken tot alleen interacties of hoge blokkerende duur of door drempels te verlagen.
Observeer lange animatiekaders met interacties
Om inzichten te verkrijgen die verder gaan dan alleen het inp -lange animatiekader, kunt u naar alle broodjes kijken met interacties (die kunnen worden gedetecteerd door de aanwezigheid van een firstUIEventTimestamp
-waarde) met een hoge blockingDuration
.
Dit kan ook een gemakkelijkere methode zijn om INP -broodjes te bewaken in plaats van te proberen de twee te correleren, die complexer kunnen zijn. In de meeste gevallen omvat dit het INP -brood voor een bepaald bezoek, en in zeldzame gevallen, wanneer het dat niet doet, komt het nog steeds op lange interacties die belangrijk zijn om op te lossen, omdat ze de Inp -interactie voor andere gebruikers kunnen zijn.
De volgende code registreert alle brooditems met een blockingDuration
groter dan 100 milliseconden waar een interactie plaatsvond tijdens het frame. De 100 wordt hier gekozen omdat het minder is dan de 200 milliseconde "goede" inp -drempel. U kunt een hogere of lagere waarde kiezen, afhankelijk van uw behoeften.
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 animatiekaders met hoge blokkerende duur
Als een verbetering van alle lange animatiekaders met interacties, wilt u misschien alle lange animatiekaders met hoge blokkerende duur bekijken. Deze duiden op mogelijke INP -problemen als een gebruiker tijdens deze lange animatiekaders interageert.
De volgende code registreert alle brooditems met een blokkeerduur groter dan 100 milliseconden waar een interactie plaatsvond tijdens het frame. De 100 wordt hier gekozen omdat het minder is dan de 200 milliseconde "goede" INP -drempel om potentiële probleemframes te helpen identificeren, terwijl de hoeveelheid lange animatiekaders tot een minimum worden gerapporteerd. U kunt een hogere of lagere waarde kiezen, afhankelijk van uw behoeften.
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 animatiekaders tijdens kritieke UI -updates om de soepelheid te verbeteren
Zoals eerder vermeld, kan het bekijken van hoge blokkeerduur lange animatiekaders helpen om de responsiviteit van de invoer aan te pakken. Maar voor gladheid moet je met een lange duration
naar alle lange animatiekaders kijken.
Omdat dit behoorlijk luidruchtig kan worden, wil je misschien metingen hiervan 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 ergste lange animatiekaders
In plaats van een ingestelde drempel te hebben, willen sites misschien gegevens verzamelen over het langste animatiekader (of frames), om de hoeveelheid gegevens te verminderen die moet worden beaaconed. Dus het maakt niet uit hoeveel lange animatiekaders een pagina -ervaringen, alleen gegevens voor de slechtste, vijf, tien of wat veel lange animatiekaders absoluut noodzakelijk zijn, zijn terug.
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 10 slechtste broodjes, met interacties, langer dan 100 milliseconden.
Op het juiste moment ( idealiter op het evenement visibilitychange
) baken terug naar analyse. Voor lokale testen kunt u console.table
periodiek gebruiken:
console.table(longestBlockingLoAFs);
Identificeer gemeenschappelijke patronen in lange animatiekaders
Een alternatieve strategie zou zijn om te kijken naar gemeenschappelijke scripts die het meest verschijnen in lange animatiekaderitems. Gegevens kunnen worden gerapporteerd op een script- en tekenpositieniveau om herhaalde overtreders 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 gemeenschappelijke scripts-of oorsprong van derden-in lange animatiekaders kunnen worden samengevat en gerapporteerd om gemeenschappelijke bijdragers aan lange animatiekaders op een site of een verzameling sites te identificeren. Bijvoorbeeld om naar URL's te 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 voorbeeld van deze output 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 lange animatiekaders API in tooling
De API maakt ook extra ontwikkelaarstools mogelijk voor lokale foutopsporing. Hoewel sommige tooling zoals Lighthouse en Chrome Devtools veel van deze gegevens hebben kunnen verzamelen met behulp van lager niveau traceringsdetails, zou het hebben van deze API op een hoger niveau andere hulpmiddelen kunnen krijgen om toegang te krijgen tot deze gegevens.
Surface Long Animation Frames Gegevens in Devtools
U kunt lange animatiekaders in Devtools naar voren komen met behulp van de performance.measure()
API, die vervolgens worden weergegeven in de DevTools -gebruikerstimings Track in prestatietraces om te laten zien waar u uw inspanningen voor prestatieverbeteringen kunt concentreren. Met behulp van de Devtools Extensibility API kunnen deze zelfs in hun eigen spoor 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 });
Lange termijn op langere termijn zullen waarschijnlijk worden opgenomen in Devtools zelf, maar door het vorige codefragment kan het daar ondertussen worden opgedoken.
De eerste invoer in de vorige figuur laat ook zien waar de browser verschillende taken samen heeft verwerkt in hetzelfde lange animatiekader in plaats van ertussen weer te geven. Zoals eerder vermeld, kan dit gebeuren wanneer er geen invoertaken met hoge prioriteit zijn, maar er is een wachtrij van taken. De eerste lange taak heeft enkele render -updates om te voltooien (anders zou het huidige lange animatiekader erna worden gereset, en een nieuwe zou beginnen met de volgende taak), maar in plaats van die weergave onmiddellijk, heeft de browser een aantal verwerkt Aanvullende taken en vervolgens vervolgens de lange render -taak behaald en het lange animatiekader beëindigd. Dit toont het nut van kijken naar lange animatiekaders in Devtools, in plaats van alleen lange taken, om vertraagde renders te helpen identificeren.
Gebruik lange animatiekaders gegevens in andere ontwikkelaarstools
De Web Vitals Extension heeft de waarde aangetoond in de logboekingsoverzicht Debug -informatie om prestatieproblemen te diagnosticeren.
Het komt nu ook op voor elke INP -callback en elke interactie: elke interactie:
Gebruik lange animatiekaders gegevens in geautomatiseerde testtools
Evenzo geautomatiseerde testhulpmiddelen in CI/CD -pijpleidingen kunnen details over potentiële prestatieproblemen oppervlak door lange animatiekaders te meten terwijl verschillende testsuites worden uitgevoerd.
FAQ
Sommige van de veelgestelde vragen over deze API zijn:
Waarom niet gewoon de API van de lange taken uitbreiden of herhalen?
Dit is een alternatieve kijk op het melden van een soortgelijke - maar uiteindelijk anders - gemeten van potentiële responsiviteitsproblemen. Het is belangrijk om ervoor te zorgen dat sites die afhankelijk zijn van de bestaande lange taken die API blijft functioneren, functioneren om het verstoren van bestaande use cases te voorkomen.
Hoewel de lange taken API kunnen profiteren van sommige kenmerken van brood (zoals een beter attributiemodel), zijn we van mening dat het concentreren op frames in plaats van taken veel voordelen biedt die dit een fundamenteel andere API maken dan de bestaande lange taken API.
Waarom heb ik geen scriptvermeldingen?
Dit kan erop wijzen dat het lange animatiekader niet te wijten was aan Javascipt, maar in plaats daarvan vanwege groot renderwerk.
Dit kan ook gebeuren wanneer het lange animatiekader te wijten is aan JavaScript, maar wanneer de scriptschrijving niet kan worden verstrekt om verschillende privacyredenen zoals eerder opgemerkt (voornamelijk dat JavaScript niet eigendom is van de pagina).
Waarom heb ik scriptitems, maar nee of beperkte broninformatie?
Dit kan om een aantal redenen gebeuren, waaronder dat er geen goede bron is om naar te wijzen .
Scriptinformatie zal ook worden beperkt tot alleen de sourceURL
(exclusief omleidingen) voor no-cors cross-origin
scripts, met een lege string voor de sourceFunctionName
en een -1
voor sourceCharPosition
. Dit kan worden opgelost door die scripts op te halen met behulp van Cors door crossOrigin = "anonymous"
toe te voegen aan het <script>
-gespanning.
Het standaard Google Tag Manager -script dat moet worden toegevoegd aan de pagina:
<!-- 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 verbeterd om j.crossOrigin = "anonymous"
toe te voegen om volledige toeschrijvingsdetails te laten worden verstrekt voor GTM.
Zal dit de lange taken API vervangen?
Hoewel we geloven dat de lange animatie -frames API een betere, meer complete API is voor het meten van lange taken, zijn er op dit moment geen plannen om de Long -taken API te verdubbelen.
Feedback gezocht
Feedback kan worden gegeven op de lijst met GitHub -problemen , of bugs in de implementatie van de API door Chrome kunnen worden ingediend in de uitgave -tracker van Chrome .
Conclusie
De lange animatie frames API is een opwindende nieuwe API met veel potentiële voordelen ten opzichte van de vorige Long Taken API.
Het blijkt een belangrijk hulpmiddel 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 probeert het identificeren en aanpakken van problemen voor ontwikkelaars gemakkelijker te maken.
De reikwijdte van de Long Animation Frames API reikt echter verder dan alleen INP, en het kan helpen andere oorzaken van trage updates te identificeren die de algehele soepelheid van de gebruikerservaring van een website kunnen beïnvloeden.
Dankbetuigingen
Thumbnail -afbeelding door Henry wees op Unsplash .