API Long Animation Frames

L'API Long Animation Frames (LoAF, pronunciato Lo-Af) è un aggiornamento dell'API Long Tasks che offre una migliore comprensione degli aggiornamenti dell'interfaccia utente lenta. Questo può essere utile per identificare i frame di animazione lenti che potrebbero influire sulla metrica Core Web Vitals Interaction to Next Paint (INP), che misura la reattività, oppure per identificare altri jank dell'UI che influiscono sulla smoothness.

Stato dell'API

Supporto dei browser

  • 123
  • x
  • x
  • x

A seguito di una prova dell'origine da Chrome 116 a Chrome 122, l'API LoAF è stata spedita da Chrome 123.

L'API Long Tasks

Supporto dei browser

  • 58
  • 79
  • x
  • x

Fonte

L'API Long Animation Frames è un'alternativa all'API Long Tasks che è disponibile in Chrome da un po' di tempo (da Chrome 58). Come suggerisce il nome, l'API Long Task consente di monitorare le attività lunghe, ovvero le attività che occupano il thread principale per almeno 50 millisecondi. Le attività lunghe possono essere monitorate utilizzando l'interfaccia di PerformanceLongTaskTiming, con una PeformanceObserver:

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

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

Le attività lunghe potrebbero causare problemi di reattività. Se un utente cerca di interagire con una pagina, ad esempio facendo clic su un pulsante o aprire un menu, ma il thread principale ha già a che fare con un'attività lunga, l'interazione dell'utente viene ritardata in attesa del completamento dell'attività.

Per migliorare la reattività, si consiglia spesso di suddividere attività lunghe. Se invece ogni attività lunga viene suddivisa in una serie di attività multiple e più piccole, potrebbe consentire l'esecuzione di attività più importanti tra le due, per evitare ritardi significativi nella risposta alle interazioni.

Perciò, quando si cerca di migliorare la reattività, la prima cosa da fare è spesso eseguire un test delle prestazioni ed esaminare attività lunghe. Ad esempio, potresti utilizzare uno strumento di controllo basato su lab come Lighthouse (che prevede il controllo Evita attività lunghe del thread principale) o esaminare attività lunghe in Chrome DevTools.

I test basati su lab sono spesso un punto di partenza scadente per identificare i problemi di reattività, poiché questi strumenti potrebbero non includere le interazioni: quando lo sono, sono un piccolo sottoinsieme di interazioni probabili. Idealmente, dovresti misurare le cause delle interazioni lente sul campo.

Carenze dell'API Long Tasks

Misurare attività lunghe sul campo con un osservatore del rendimento è solo in qualche modo utile. In realtà, non fornisce così tante informazioni oltre al fatto che si è verificata un'attività lunga e alla durata di questa attività.

Gli strumenti per il monitoraggio degli utenti reali (RUM) spesso la utilizzano per determinare l'andamento del numero o della durata delle attività lunghe o per identificare le pagine su cui si verificano, ma senza i dettagli sottostanti su ciò che ha causato l'attività lunga, l'utilizzo è limitato. L'API Long Tasks dispone solo di un modello di attribuzione di base, che nella migliore dei casi indica solo il contenitore in cui si è verificata l'attività lunga (il documento di primo livello o un <iframe>), ma non lo script o la funzione che l'ha chiamato, come mostrato da una voce tipica:

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

Anche l'API Long Tasks è una visualizzazione incompleta, poiché potrebbe escludere anche alcune attività importanti. Alcuni aggiornamenti, come il rendering, avvengono in attività separate che idealmente dovrebbero essere incluse insieme all'esecuzione precedente che ha portato l'aggiornamento a misurare accuratamente il "lavoro totale" di quell'interazione. Per ulteriori dettagli sui limiti dell'utilizzo delle attività, consulta la sezione "Dove le attività lunghe non sono sufficienti" dell'articolo esplicativo.

L'ultimo problema è che la misurazione delle attività lunghe genera report solo su singole attività che richiedono più tempo del limite di 50 millisecondi. Un frame dell'animazione potrebbe essere composto da diverse attività al di sotto di questo limite di 50 millisecondi, ma collettivamente continuano a bloccare la capacità del browser di eseguire il rendering.

L'API Long Animation Frames

Supporto dei browser

  • 123
  • x
  • x
  • x

L'API Long Animation Frames (LoAF) è una nuova API che cerca di risolvere alcuni dei difetti dell'API Long Tasks per consentire agli sviluppatori di ottenere informazioni più strategiche per risolvere i problemi di reattività e migliorare l'INP.

Una buona reattività indica che una pagina risponde rapidamente alle interazioni con la pagina. Ciò significa poter applicare gli aggiornamenti necessari all'utente in modo tempestivo ed evitare di bloccarli. Per INP, si consiglia di rispondere entro 200 millisecondi o meno, ma per altri aggiornamenti (ad esempio le animazioni) anche quelli che potrebbero essere troppo lunghi.

L'API Long Animation Frames è un approccio alternativo alla misurazione del lavoro di blocco. Anziché misurare le singole attività, l'API Long Animation Frames, come suggerisce il nome, misura i frame di animazione lunghi. Un frame dell'animazione lungo si verifica quando un aggiornamento del rendering viene ritardato di oltre 50 millisecondi (lo stesso della soglia per l'API Long Tasks).

I frame di animazione lunghi possono essere osservati in modo simile alle attività lunghe con un PerformanceObserver, ma esaminando invece il tipo long-animation-frame:

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

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

Puoi eseguire query sui frame di animazione lunghi precedenti anche nella Sequenza temporale del rendimento, ad esempio:

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

Tuttavia, c'è un maxBufferSize per le voci relative al rendimento dopo il quale vengono eliminate le voci più recenti, quindi l'approccio PerformanceObservationr è l'approccio consigliato. La dimensione del buffer long-animation-frame è impostata su 200, come nel caso di long-tasks.

Vantaggi dell'analisi dei frame anziché delle attività

Il vantaggio principale di guardare questo aspetto dal punto di vista del frame piuttosto che delle attività è che un'animazione lunga può essere composta da un numero qualsiasi di attività che cumulativamente hanno generato un lungo frame dell'animazione. Questo risponde al punto finale citato in precedenza, dove la somma di molte attività più piccole che bloccano la visualizzazione prima di un frame di animazione potrebbe non essere visualizzata dall'API Long Tasks.

Un ulteriore vantaggio di questa visualizzazione alternativa per attività lunghe è la possibilità di fornire suddivisioni temporali dell'intero frame. Anziché includere solo un startTime e un duration, come l'API Long Tasks, LoAF include un'analisi molto più dettagliata delle varie parti della durata del frame, tra cui:

  • startTime: l'ora di inizio del frame dell'animazione lungo rispetto al momento di inizio della navigazione.
  • duration: la durata del frame dell'animazione lungo (esclusa la durata della presentazione).
  • renderStart: l'ora di inizio del ciclo di rendering, che include requestAnimationFrame callback, calcolo di stile e layout, ridimensionamento dell'osservatore e dell'osservatore delle intersezioni.
  • styleAndLayoutStart: l'inizio del periodo di tempo dedicato ai calcoli relativi a stile e layout.
  • firstUIEventTimestamp: l'ora del primo evento UI (mouse/tastiera e così via) da gestire nel corso di questo frame.
  • blockingDuration: la durata in millisecondi durante la quale il frame dell'animazione è stato bloccato.

Questi timestamp consentono di suddividere il frame dell'animazione lungo in tempi:

Durata Calcolo
Ora di inizio startTime
Ora di fine startTime + duration
Durata lavoro renderStart ? renderStart - startTime : duration
Durata rendering renderStart ? (startTime + duration) - renderStart: 0
Rendering: durata pre-layout styleAndLayoutStart ? styleAndLayoutStart - renderStart : 0
Rendering: durata di stile e layout styleAndLayoutStart ? (startTime + duration) - styleAndLayoutStart : 0

Per ulteriori dettagli su questi tempi, consulta la spiegazione, che fornisce dettagli più dettagliati su quale attività contribuisce a un lungo frame dell'animazione.

Migliore attribuzione

Il tipo di voce long-animation-frame include dati di attribuzione migliori per ogni script che ha contribuito a creare un lungo frame dell'animazione.

Analogamente all'API Long Tasks, viene fornito in un array di voci di attribuzione, ciascuna delle quali include dettagli:

  • Un elemento name e un EntryType restituiranno entrambi script.
  • Un elemento invoker significativo che indica il modo in cui è stato chiamato lo script (ad esempio 'IMG#id.onload', 'Window.requestAnimationFrame' o 'Response.json.then').
  • Il invokerType del punto di ingresso dello script:
    • user-callback: un callback noto registrato da un'API di piattaforma web (ad esempio, setTimeout, requestAnimationFrame).
    • event-listener: un listener per un evento della piattaforma (ad esempio click, load, keyup).
    • resolve-promise: gestore di una promessa relativa a una piattaforma (ad esempio, fetch(). Tieni presente che, nel caso delle promesse, tutti i gestori delle stesse promesse vengono combinati in un unico "script").
    • reject-promise: come da resolve-promise, ma per il rifiuto.
    • classic-script: valutazione dello script (ad esempio, <script> o import())
    • module-script: uguale a classic-script, ma per gli script di moduli.
  • Separa i dati relativi alla tempistica per lo script:
    • startTime: ora in cui la funzione di voce è stata richiamata.
    • duration: la durata tra il giorno startTime e il termine dell'elaborazione della coda delle microattività successiva.
    • executionStart: l'ora dopo la compilazione.
    • forcedStyleAndLayoutDuration: il tempo totale dedicato all'elaborazione del layout/stile forzato all'interno di questa funzione (vedi thrashing).
    • pauseDuration: tempo totale impiegato per "mettere in pausa" le operazioni sincrone (avviso, XHR sincrono).
  • Dettagli sull'origine dello script:
    • sourceURL: il nome della risorsa di script dove disponibile (o vuoto se non viene trovata).
    • sourceFunctionName: il nome della funzione script se disponibile (o vuoto se non lo trovi).
    • sourceCharPosition: la posizione del carattere dello script se disponibile (o -1 se non trovata).
  • windowAttribution: il contenitore (il documento di primo livello o un <iframe>) in cui si trovava il frame dell'animazione lungo.
  • window: un riferimento alla finestra della stessa origine.

Ove fornite, le voci di origine consentono agli sviluppatori di sapere esattamente come è stato chiamato ogni script nel lungo frame dell'animazione, fino alla posizione del carattere nello script di chiamata. Questo fornisce la posizione esatta in una risorsa JavaScript che ha generato il lungo frame dell'animazione.

Esempio di una voce relativa al rendimento long-animation-frame

Un esempio completo di voce di rendimento long-animation-frame, contenente un singolo script, è:

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

Come si può vedere, questa fornisce una quantità di dati senza precedenti per consentire ai siti web di comprendere la causa degli aggiornamenti lenti del rendering.

Abilitazione dell'API Long Animation Frames

L'API Long Animation Frames è attivata per impostazione predefinita su Chrome 123.

Utilizzo dell'API Long Animation Frames sul campo

Strumenti come Lighthouse, sebbene utili per l'individuazione e la riproduzione dei problemi, sono strumenti di laboratorio che possono trascurare aspetti importanti dell'esperienza utente che solo i dati sul campo possono fornire. L'API Long Animation Frames può essere utilizzata sul campo per raccogliere dati contestuali importanti per le interazioni degli utenti che l'API Long Tasks non potrebbe. Questo può aiutarti a individuare e riprodurre problemi di interattività che altrimenti non avresti scoperto.

Di seguito sono elencate alcune strategie suggerite, ma il team di Chrome vorrebbe ricevere feedback su questa API e su come sviluppatori e fornitori di RUM potrebbero vedere se stessi utilizzando le informazioni fornite dall'API.

Supporto dell'API Long Animation Frames per rilevamento della funzionalità

Per verificare se l'API è supportata, puoi utilizzare il seguente codice:

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

In questo caso è possibile utilizzare la seguente alternativa, mentre i frame dell'animazione lunghi non sono ancora supportati per impostazione predefinita e si trovano in questo stato di transizione:

if ('PerformanceLongAnimationFrameTiming' in window) {
  // Monitor LoAFs
}

Segnalazione di dati di animazione lunghi a un endpoint di analisi

Come mostrato, la voce relativa al rendimento LoAF include informazioni preziose. Una strategia potrebbe essere quella di monitorare tutti i LoAF e beacon di quelli al di sopra di una certa soglia per tornare a un endpoint di analisi per un’analisi successiva:

const REPORTING_THRESHOLD_MS = 150;

const observer = new PerformanceObserver(list => {
  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 });

Poiché le voci relative a frame dell'animazione lunghi possono essere molto grandi, gli sviluppatori dovrebbero decidere quali dati della voce inviare ad Analytics. Ad esempio, gli orari di riepilogo della voce e magari i nomi degli script o qualche altro insieme minimo di altri dati contestuali che possono essere ritenuti necessari.

Osservazione dei fotogrammi dell'animazione lunghi peggiori

I siti potrebbero voler raccogliere dati sul frame dell'animazione più lungo (o sui frame) per ridurre il volume di dati da sottoporre a beaconing. Quindi, a prescindere da quanti frame di animazione lunghi vengono visualizzati in una pagina, vengono trasmessi solo i dati relativi all'uno, ai cinque o al numero di frame di animazione lunghi assolutamente necessari.

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

Al momento giusto (idealmente durante l'evento visibilitychange), il beacon tornerà ad Analytics. Per i test locali, puoi utilizzare console.table periodicamente:

console.table(longestBlockingLoAFs);

Collegamento all'interazione INP più lunga

Come estensione dell'osservazione dei peggiori LoAF, i frame LoAF corrispondenti alla voce INP potrebbero essere utilizzati come dati di attribuzione per fornire ulteriori dettagli su come migliorare l'INP.

Al momento non esiste un'API diretta per collegare una voce INP alla relativa voce o alle relative voci LoAF, anche se è possibile farlo nel codice confrontando l'ora di inizio e l'ora di fine di ognuna (vedi questo script di esempio).

Report su frame di animazione lunghi con interazioni

Un approccio alternativo che richiede meno codice sarebbe inviare sempre le voci LoAF più grandi (o top X più grandi) in cui si è verificata un'interazione durante il frame (che può essere rilevata dalla presenza di un valore firstUIEventTimestamp). Nella maggior parte dei casi, è inclusa l'interazione INP per una determinata visita e, in rari casi in cui non viene visualizzata, vengono comunque visualizzate interazioni lunghe che è importante risolvere, in quanto potrebbero essere l'interazione INP per altri utenti.

Il codice seguente registra tutte le voci LoAF superiori a 150 millisecondi in cui si è verificata un'interazione durante il frame. Il valore 150 viene scelto qui perché è leggermente inferiore alla soglia INP "buona" di 200 millisecondi. Puoi scegliere un valore superiore o inferiore a seconda delle tue esigenze.

const REPORTING_THRESHOLD_MS = 150;

const observer = new PerformanceObserver(list => {
    for (const entry of list.getEntries()) {
      if (entry.duration > 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 });

Identificazione di schemi comuni nei fotogrammi di animazione lunghi

Una strategia alternativa consiste nell'esaminare gli script comuni che appaiono più spesso nelle voci di frame di animazione lunghi. I dati potrebbero essere riportati a livello di script e/o di posizione del carattere per identificare i trasgressori recidivi.

Questo metodo può funzionare in particolare per le piattaforme personalizzabili in cui temi o plug-in che causano problemi di prestazioni potrebbero essere identificati più facilmente su diversi siti.

Il tempo di esecuzione di script comuni, o origini di terze parti, nei lunghi frame di animazione può essere sommato e riportato per identificare i fattori comuni per i fotogrammi di animazione lunghi su un sito o una raccolta di siti. Ad esempio, per esaminare gli URL:

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

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

Ecco un esempio di questo output:

(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

Utilizzo dell'API Long Animation Frames negli strumenti

L'API potrebbe inoltre consentire agli sviluppatori di utilizzare ulteriori strumenti per il debug locale. Anche se alcuni strumenti come Lighthouse e Chrome DevTools sono stati in grado di raccogliere gran parte di questi dati utilizzando dettagli di tracciamento di livello inferiore, la presenza di questa API di livello superiore potrebbe consentire ad altri strumenti di accedere a questi dati.

Visualizzazione dei dati di frame di animazione lunghi in DevTools

Puoi visualizzare frame di animazione lunghi in DevTools utilizzando l'API performance.measure(), che vengono poi visualizzati nel canale di sincronizzazione utente di DevTools nelle tracce delle prestazioni per mostrare dove concentrare i tuoi sforzi per migliorare le prestazioni:

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    performance.measure('LoAF', {
      start: entry.startTime,
      end: entry.startTime + entry.duration,
    });
  }
});

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

Se questa API si rivela utile a lungo termine, è probabile che venga incorporata nello stesso strumento DevTools, ma nel frattempo lo snippet di codice precedente consente di visualizzarla.

Usare dati di frame di animazione lunghi in altri strumenti per sviluppatori

L'estensione Web Vitals ha dimostrato di essere importante nel logging delle informazioni di debug di riepilogo per diagnosticare i problemi di prestazioni. Ora il lancio dell'API, strumenti come questo potrebbero far emergere più facilmente i dati per aiutare gli sviluppatori a sapere dove concentrare i loro sforzi. Abbiamo inoltre in programma di aggiungere questa funzionalità alla libreria JavaScript di Web Vitals nella versione 4.

Utilizzare i dati di frame di animazione lunghi negli strumenti di test automatici

Analogamente, gli strumenti di test automatici, magari in pipeline CI/CD, potrebbero mostrare dettagli su potenziali problemi di rendimento misurando lunghi frame di animazione durante l'esecuzione di varie suite di test.

Domande frequenti

Ecco alcune delle domande frequenti su questa API:

Perché non estendere o ripetere l'API Long Tasks?

Questo è uno sguardo alternativo alla generazione di report con una misurazione simile, ma in definitiva, diversa, dei potenziali problemi di reattività. È importante assicurarsi che i siti che si basano sull'API Long Tasks esistente continuino a funzionare per evitare di compromettere i casi d'uso esistenti.

Sebbene l'API Long Tasks possa trarre vantaggio da alcune delle funzionalità di LoAF (come un modello di attribuzione migliore), riteniamo che concentrarsi sui frame anziché sulle attività offra molti vantaggi che rendono questa API sostanzialmente diversa dall'API Long Tasks esistente.

Questo sostituirà l'API Long Tasks?

Riteniamo che l'API Long Animation Frames sia un'API migliore e più completa per misurare attività lunghe, ma al momento non è prevista la deprecazione dell'API Long Tasks.

Feedback desiderato

Puoi fornire feedback nell'elenco dei problemi di GitHub oppure segnalare bug nell'implementazione dell'API in Chrome nello strumento Issue Tracker di Chrome.

Conclusione

L'API Long Animation Frames è una nuova entusiasmante API con molti potenziali vantaggi rispetto alla precedente API Long Tasks.

Si sta rivelando uno strumento fondamentale per risolvere i problemi di reattività misurati dall'INP. L'INP è una metrica complessa da ottimizzare e questa API è uno dei modi in cui il team di Chrome sta cercando di semplificare l'identificazione e la risoluzione dei problemi per gli sviluppatori.

L'ambito dell'API Long Animation Frames va oltre l'INP e può aiutare a identificare altre cause di aggiornamenti lenti che possono influire sull'uniformità generale dell'esperienza utente su un sito web.

Ringraziamenti

Immagine in miniatura di Henry Be su Unsplash.