Trova interazioni lente sul campo

Scopri come trovare le interazioni lente nei dati sul campo del tuo sito web per trovare opportunità di migliorare l'Interaction to Next Paint.

I dati sul campo sono dati che indicano l'esperienza degli utenti reali sul tuo sito web. Individua problemi che non puoi trovare solo nei dati di laboratorio. Per quanto riguarda l'Interaction to Next Paint (INP), i dati sul campo sono essenziali per identificare le interazioni lente e forniscono indizi fondamentali per aiutarti a risolverle.

In questa guida scoprirai come valutare rapidamente l'INP del tuo sito web utilizzando i dati sul campo del Report sull'esperienza utente di Chrome (CrUX) per verificare se il tuo sito web presenta problemi con l'INP. Successivamente, imparerai a utilizzare la build di attribuzione della libreria JavaScript web-vitals e i nuovi approfondimenti forniti dall'API Long Animation Frames (LoAF) per raccogliere e interpretare i dati sul campo relativi alle interazioni lente sul tuo sito web.

Inizia con CrUX per valutare l'INP del tuo sito web

Se non raccogli dati sul campo dagli utenti del tuo sito web, CrUX potrebbe essere un buon punto di partenza. CrUX raccoglie i dati sul campo da utenti reali di Chrome che hanno attivato l'invio dei dati di telemetria.

I dati CrUX vengono visualizzati in diverse aree e dipendono dall'ambito delle informazioni che stai cercando. CrUX può fornire dati su INP e altri Segnali web essenziali per:

  • Singole pagine e intere origini utilizzando PageSpeed Insights.
  • Tipi di pagine. Ad esempio, molti siti web di e-commerce hanno tipi di pagine dei dettagli del prodotto e pagine di elenco dei prodotti. Puoi ottenere i dati CrUX per i tipi di pagine unici in Search Console.

Come punto di partenza, puoi inserire l'URL del tuo sito web in PageSpeed Insights. Una volta inserito l'URL, i dati dei campi, se disponibili, verranno visualizzati per più metriche, inclusa l'INP. Puoi anche utilizzare i pulsanti di attivazione/disattivazione per controllare i valori INP per le dimensioni mobile e desktop.

Dati sul campo mostrati da CrUX in PageSpeed Insights, che mostrano LCP, INP, CLS come tre metriche Core Web Vitals e TTFB, FCP come metriche diagnostiche e FID come metrica Core Web Vitals ritirata.
Una lettura dei dati CrUX come visualizzati in PageSpeed Insights. In questo esempio, l'INP della pagina web specificata richiede miglioramenti.

Questi dati sono utili perché ti indicano se hai un problema. Ciò che CrUX non può fare, tuttavia, è dirti cosa sta causando problemi. Esistono molte soluzioni di monitoraggio degli utenti reali (RUM) disponibili che ti aiuteranno a raccogliere i tuoi dati sul campo dagli utenti del tuo sito web per rispondere a questa domanda. Un'opzione è raccogliere i dati sul campo utilizzando la libreria JavaScript web-vitals.

Raccogliere i dati dei campi con la libreria JavaScript web-vitals

La libreria JavaScript web-vitals è uno script che puoi caricare sul tuo sito web per raccogliere i dati dei campi degli utenti del tuo sito web. Puoi utilizzarlo per registrare una serie di metriche, tra cui INP nei browser che lo supportano.

Browser Support

  • Chrome: 96.
  • Edge: 96.
  • Firefox Technology Preview: supported.
  • Safari: not supported.

Source

La build standard della libreria web-vitals può essere utilizzata per ottenere dati INP di base dagli utenti sul campo:

import {onINP} from 'web-vitals';

onINP(({name, value, rating}) => {
  console.log(name);    // 'INP'
  console.log(value);   // 512
  console.log(rating);  // 'poor'
});

Per analizzare i dati dei campi degli utenti, devi inviarli a una destinazione:

import {onINP} from 'web-vitals';

onINP(({name, value, rating}) => {
  // Prepare JSON to be sent for collection. Note that
  // you can add anything else you'd want to collect here:
  const body = JSON.stringify({name, value, rating});

  // Use `sendBeacon` to send data to an analytics endpoint.
  // For Google Analytics, see https://github.com/GoogleChrome/web-vitals#send-the-results-to-google-analytics.
  navigator.sendBeacon('/analytics', body);
});

Tuttavia, questi dati da soli non ti dicono molto di più di CrUX. È qui che entra in gioco la build di attribuzione della libreria web-vitals.

Ottieni di più con la build di attribuzione della libreria web-vitals

La compilazione dell'attribuzione della libreria web-vitals mostra dati aggiuntivi che puoi ottenere dagli utenti sul campo per aiutarti a risolvere meglio le interazioni problematiche che influiscono sull'INP del tuo sito web. Questi dati sono accessibili tramite l'oggetto attribution visualizzato nel metodo onINP() della libreria:

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

onINP(({name, value, rating, attribution}) => {
  console.log(name);         // 'INP'
  console.log(value);        // 56
  console.log(rating);       // 'good'
  console.log(attribution);  // Attribution data object
});
Come vengono visualizzati i log della console dalla libreria web-vitals. La console in questo esempio mostra il nome della metrica (INP), il valore INP (56), la posizione di questo valore all'interno delle soglie INP (buono) e le varie informazioni mostrate nell'oggetto di attribuzione, incluse le voci dell'API Long Animation Frames.
Come vengono visualizzati i dati della libreria web-vitals nella console.

Oltre all'INP della pagina, la creazione dell'attribuzione fornisce molti dati che puoi utilizzare per comprendere i motivi delle interazioni lente, inclusa la parte dell'interazione su cui devi concentrarti. Può aiutarti a rispondere a domande importanti come:

  • "L'utente ha interagito con la pagina durante il caricamento?"
  • "I gestori eventi dell'interazione sono stati eseguiti a lungo?"
  • "Il codice del gestore di eventi di interazione è stato ritardato all'avvio? Se sì, cos'altro stava succedendo nel thread principale in quel momento?"
  • "L'interazione ha causato un'attività di rendering che ha ritardato il rendering del frame successivo?"

La tabella seguente mostra alcuni dei dati di attribuzione di base che puoi ottenere dalla libreria e che possono aiutarti a capire alcune cause generali delle interazioni lente sul tuo sito web:

attribution chiave dell'oggetto Dati
interactionTarget Un selettore CSS che punta all'elemento che ha prodotto il valore INP della pagina, ad esempio button#save.
interactionType Il tipo di interazione, ovvero clic, tocchi o input da tastiera.
inputDelay* Il ritardo input dell'interazione.
processingDuration* Il tempo che intercorre tra l'inizio dell'esecuzione del primo listener di eventi in risposta all'interazione dell'utente e il termine dell'elaborazione di tutti i listener di eventi.
presentationDelay* Il ritardo di presentazione dell'interazione, che si verifica a partire dal momento in cui i gestori di eventi terminano fino al momento in cui viene disegnato il frame successivo.
longAnimationFrameEntries* Voci dell'elenco delle app attive associate all'interazione. Per ulteriori informazioni, consulta la pagina successiva.
*Novità della versione 4

A partire dalla versione 4 della libreria web-vitals, puoi ottenere informazioni ancora più approfondite sulle interazioni problematiche grazie ai dati forniti con le suddivisioni delle fasi INP (ritardo di input, durata dell'elaborazione e ritardo di presentazione) e l'API Long Animation Frames (LoAF).

API Long Animation Frames (LoAF)

Browser Support

  • Chrome: 123.
  • Edge: 123.
  • Firefox: not supported.
  • Safari: not supported.

Source

Il debug delle interazioni utilizzando i dati dei campi è un'attività impegnativa. Con i dati di LoAF, tuttavia, ora è possibile ottenere informazioni più approfondite sulle cause delle interazioni lente, in quanto LoAF espone una serie di tempistiche dettagliate e altri dati che puoi utilizzare per individuare le cause precise e, cosa ancora più importante, la posizione dell'origine del problema nel codice del tuo sito web.

La build di attribuzione della libreria web-vitals espone un array di voci LoAF nella chiave longAnimationFrameEntries dell'oggetto attribution. La tabella seguente elenca alcuni dati chiave che puoi trovare in ogni voce di LoAF:

Chiave dell'oggetto di entrata LoAF Dati
duration La durata del frame dell'animazione lungo, fino al termine del layout, ma escludendo la pittura e la composizione.
blockingDuration La quantità totale di tempo nel frame in cui il browser non è riuscito a rispondere rapidamente a causa di attività lunghe. Questo tempo di blocco può includere attività lunghe che eseguono JavaScript, nonché qualsiasi attività di rendering lunga successiva nel frame.
firstUIEventTimestamp Il timestamp di quando l'evento è stato messo in coda durante il frame. Utile per capire l'inizio del ritardo di input di un'interazione.
startTime Il timestamp di inizio del frame.
renderStart Quando è iniziato il lavoro di rendering del frame. Sono inclusi tutti i callback requestAnimationFrame (e i callback ResizeObserver, se applicabili), ma potenzialmente prima dell'inizio di qualsiasi lavoro di stile/layout.
styleAndLayoutStart Quando si verifica un'operazione di stile/layout nel frame. Può essere utile per capire la durata del lavoro di stile/layout quando si considerano altri timestamp disponibili.
scripts Un array di elementi contenenti informazioni sull'attribuzione degli script che contribuiscono all'INP della pagina.
Una visualizzazione di un frame dell'animazione lungo in base al modello LoAF.
Un diagramma delle tempistiche di un frame dell'animazione lungo in base all'API LoAF (meno blockingDuration).

Tutte queste informazioni possono dirti molto su cosa rallenta un'interazione, ma l'array scripts che mostrano le voci LoAF dovrebbe essere di particolare interesse:

Chiave dell'oggetto di attribuzione dello script Dati
invoker L'invoker. Può variare in base al tipo di chiamante descritto nella riga successiva. Esempi di invoker possono essere valori come 'IMG#id.onload', 'Window.requestAnimationFrame' o 'Response.json.then'.
invokerType Il tipo di invoker. Può essere 'user-callback', 'event-listener', 'resolve-promise', 'reject-promise', 'classic-script' o 'module-script'.
sourceURL L'URL dello script da cui ha origine il frame dell'animazione lungo.
sourceCharPosition La posizione del carattere nello script identificato da sourceURL.
sourceFunctionName Il nome della funzione nello script identificato.

Ogni voce di questo array contiene i dati mostrati in questa tabella, che forniscono informazioni sullo script responsabile dell'interazione lenta e sul modo in cui è responsabile.

Misurare e identificare le cause comuni delle interazioni lente

Per darti un'idea di come potresti utilizzare queste informazioni, questa guida ti mostrerà come utilizzare i dati LoAF visualizzati nella libreria web-vitals per determinare alcune cause alla base delle interazioni lente.

Durate di elaborazione lunghe

La durata dell'elaborazione di un'interazione è il tempo necessario per l'esecuzione completa dei callback del gestore di eventi registrato dell'interazione e di qualsiasi altro evento che potrebbe verificarsi nel frattempo. Durate di elaborazione elevate vengono visualizzate dalla libreria web-vitals:

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

onINP(({name, value, attribution}) => {
  const {processingDuration} = attribution; // 512.5
});

È naturale pensare che la causa principale di un'interazione lenta sia l'esecuzione troppo lunga del codice del gestore di eventi, ma non è sempre così. Una volta confermato che questo è il problema, puoi analizzare più a fondo i dati LoAF:

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

onINP(({name, value, attribution}) => {
  const {processingDuration} = attribution; // 512.5

  // Get the longest script from LoAF covering `processingDuration`:
  const loaf = attribution.longAnimationFrameEntries.at(-1);
  const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];

  if (script) {
    // Get attribution for the long-running event handler:
    const {invokerType} = script;        // 'event-listener'
    const {invoker} = script;            // 'BUTTON#update.onclick'
    const {sourceURL} = script;          // 'https://example.com/app.js'
    const {sourceCharPosition} = script; // 83
    const {sourceFunctionName} = script; // 'update'
  }
});

Come puoi vedere nello snippet di codice precedente, puoi utilizzare i dati LoAF per individuare la causa precisa di un'interazione con valori di durata dell'elaborazione elevati, tra cui:

  • L'elemento e il relativo listener di eventi registrato.
  • Il file di script e la posizione del carattere al suo interno contenente il codice del gestore di eventi a esecuzione prolungata.
  • Il nome della funzione.

Questo tipo di dati è di valore inestimabile. Non è più necessario svolgere il lavoro di ricerca per scoprire esattamente quale interazione o quale dei relativi gestori di eventi è responsabile dei valori elevati della durata dell'elaborazione. Inoltre, poiché gli script di terze parti possono spesso registrare i propri gestori di eventi, puoi determinare se la responsabilità è del tuo codice. Per il codice su cui hai il controllo, ti consigliamo di esaminare l'ottimizzazione delle attività di lunga durata.

Ritardi input prolungati

Sebbene i gestori di eventi di lunga durata siano comuni, ci sono altre parti dell'interazione da considerare. Una parte si verifica prima della durata dell'elaborazione, nota come ritardo di input. Questo è il tempo che intercorre tra l'avvio dell'interazione da parte dell'utente e il momento in cui iniziano a essere eseguite le chiamate di callback del gestore eventi e si verifica quando il thread principale sta già elaborando un'altra attività. La build di attribuzione della libreria web-vitals può indicare la durata del ritardo di input per un'interazione:

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

onINP(({name, value, attribution}) => {
  const {inputDelay} = attribution; // 125.59439536
});

Se noti che alcune interazioni hanno ritardi di input elevati, devi capire cosa stava succedendo nella pagina al momento dell'interazione che ha causato il lungo ritardo di input. Spesso si tratta di capire se l'interazione si è verificata durante il caricamento della pagina o successivamente.

Si è verificato durante il caricamento della pagina?

Il thread principale è spesso il più occupato durante il caricamento di una pagina. Durante questo periodo, vengono accodate ed elaborate tutti i tipi di attività e, se l'utente tenta di interagire con la pagina mentre tutto questo lavoro è in corso, l'interazione può essere ritardata. Le pagine che caricano molto codice JavaScript possono avviare il lavoro di compilazione e valutazione degli script, nonché l'esecuzione di funzioni che preparano una pagina per le interazioni degli utenti. Questo lavoro può interferire se l'utente interagisce mentre si svolge questa attività e puoi scoprire se è questo il caso per gli utenti del tuo sito web:

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

onINP(({name, value, attribution}) => {
  const {inputDelay} = attribution; // 125.59439536

  // Get the longest script from the first LoAF entry:
  const loaf = attribution.longAnimationFrameEntries[0];
  const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];

  if (script) {
    // Invoker types can describe if script eval blocked the main thread:
    const {invokerType} = script;    // 'classic-script' | 'module-script'
    const {sourceLocation} = script; // 'https://example.com/app.js'
  }
});

Se registri questi dati nel campo e noti ritardi di input elevati e tipi di invoker 'classic-script' o 'module-script', è giusto affermare che gli script sul tuo sito impiegano molto tempo per essere valutati e bloccano il thread principale abbastanza a lungo da ritardare le interazioni. Puoi ridurre questo tempo di blocco suddividendo gli script in bundle più piccoli, posticipando il caricamento del codice inizialmente inutilizzato a un momento successivo e controllando il tuo sito per individuare il codice inutilizzato che puoi rimuovere del tutto.

È avvenuto dopo il caricamento della pagina?

Sebbene i ritardi di input si verifichino spesso durante il caricamento di una pagina, è altrettanto possibile che si verifichino dopo il caricamento di una pagina, a causa di una causa completamente diversa. Le cause comuni dei ritardi di input dopo il caricamento della pagina possono essere codice eseguito periodicamente a causa di una chiamata setInterval precedente o anche callback di eventi accodati per l'esecuzione precedente e ancora in fase di elaborazione.

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

onINP(({name, value, attribution}) => {
  const {inputDelay} = attribution; // 125.59439536

  // Get the longest script from the first LoAF entry:
  const loaf = attribution.longAnimationFrameEntries[0];
  const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];

  if (script) {
    const {invokerType} = script;        // 'user-callback'
    const {sourceURL} = script;          // 'https://example.com/app.js'
    const {sourceCharPosition} = script; // 83
    const {sourceFunctionName} = script; // 'update'
  }
});

Come nel caso della risoluzione dei problemi relativi a valori di durata dell'elaborazione elevati, i ritardi di input elevati dovuti alle cause menzionate in precedenza forniscono dati dettagliati sull'attribuzione degli script. Ciò che cambia, tuttavia, è il tipo di chiamante, che varia in base alla natura del lavoro che ha ritardato l'interazione:

  • 'user-callback' indica che l'attività di blocco è stata eseguita da setInterval, setTimeout o persino requestAnimationFrame.
  • 'event-listener' indica che l'attività di blocco proveniva da un input precedente messo in coda e ancora in elaborazione.
  • 'resolve-promise' e 'reject-promise' indicano che l'attività di blocco è stata avviata in precedenza da un'attività asincrona e risolta o rifiutata nel momento in cui l'utente ha tentato di interagire con la pagina, ritardando l'interazione.

In ogni caso, i dati di attribuzione dello script ti daranno un'idea di dove iniziare a cercare e se il ritardo di input è dovuto al tuo codice o a quello di uno script di terze parti.

Ritardi prolungati della presentazione

I ritardi di presentazione sono l'ultimo miglio di un'interazione e iniziano al termine dei gestori di eventi dell'interazione, fino al punto in cui è stato disegnato il frame successivo. Si verificano quando il lavoro in un gestore eventi a causa di un'interazione modifica lo stato visivo dell'interfaccia utente. Come per le durate di elaborazione e i ritardi di input, la libreria web-vitals può indicarti la durata del ritardo di presentazione per un'interazione:

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

onINP(({name, value, attribution}) => {
  const {presentationDelay} = attribution; // 113.32307691
});

Se registri questi dati e noti ritardi di presentazione elevati per le interazioni che contribuiscono all'INP del tuo sito web, le cause possono variare, ma ecco un paio di motivi da tenere d'occhio.

Lavoro di stile e layout costoso

I ritardi prolungati nella presentazione possono comportare costosi ricalcoli dello stile e del layout, che derivano da una serie di cause, tra cui selettori CSS complessi e dimensioni DOM elevate. Puoi misurare la durata di questo lavoro con i tempi LoAF visualizzati nella libreria web-vitals:

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

onINP(({name, value, attribution}) => {
  const {presentationDelay} = attribution; // 113.32307691

  // Get the longest script from the last LoAF entry:
  const loaf = attribution.longAnimationFrameEntries.at(-1);
  const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];

  // Get necessary timings:
  const {startTime} = loaf; // 2120.5
  const {duration} = loaf;  // 1002

  // Figure out the ending timestamp of the frame (approximate):
  const endTime = startTime + duration; // 3122.5

  // Get the start timestamp of the frame's style/layout work:
  const {styleAndLayoutStart} = loaf; // 3011.17692309

  // Calculate the total style/layout duration:
  const styleLayoutDuration = endTime - styleAndLayoutStart; // 111.32307691

  if (script) {
    // Get attribution for the event handler that triggered
    // the long-running style and layout operation:
    const {invokerType} = script;        // 'event-listener'
    const {invoker} = script;            // 'BUTTON#update.onclick'
    const {sourceURL} = script;          // 'https://example.com/app.js'
    const {sourceCharPosition} = script; // 83
    const {sourceFunctionName} = script; // 'update'
  }
});

LoAF non ti dirà la durata del lavoro di stile e layout per un frame, ma ti dirà quando è iniziato. Con questo timestamp iniziale, puoi utilizzare altri dati di LoAF per calcolare una durata precisa del lavoro determinando l'ora di fine del frame e sottraendo il timestamp iniziale del lavoro di stile e layout.

Callback requestAnimationFrame a lunga esecuzione

Una potenziale causa di lunghi ritardi nella presentazione è l'eccessivo lavoro svolto in un callback requestAnimationFrame. I contenuti di questo callback vengono eseguiti dopo il completamento dei gestori di eventi, ma poco prima del ricalcolo dello stile e del layout.

Il completamento di questi callback può richiedere molto tempo se il lavoro svolto al loro interno è complesso. Se sospetti che i valori elevati di ritardo di presentazione siano dovuti al lavoro che stai svolgendo con requestAnimationFrame, puoi utilizzare i dati LoAF visualizzati dalla libreria web-vitals per identificare questi scenari:

onINP(({name, value, attribution}) => {
  const {presentationDelay} = attribution; // 543.1999999880791

  // Get the longest script from the last LoAF entry:
  const loaf = attribution.longAnimationFrameEntries.at(-1);
  const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];

  // Get the render start time and when style and layout began:
  const {renderStart} = loaf;         // 2489
  const {styleAndLayoutStart} = loaf; // 2989.5999999940395

  // Calculate the `requestAnimationFrame` callback's duration:
  const rafDuration = styleAndLayoutStart - renderStart; // 500.59999999403954

  if (script) {
    // Get attribution for the event handler that triggered
    // the long-running requestAnimationFrame callback:
    const {invokerType} = script;        // 'user-callback'
    const {invoker} = script;            // 'FrameRequestCallback'
    const {sourceURL} = script;          // 'https://example.com/app.js'
    const {sourceCharPosition} = script; // 83
    const {sourceFunctionName} = script; // 'update'
  }
});

Se noti che una parte significativa del tempo di ritardo della presentazione viene spesa in un callback requestAnimationFrame, assicurati che il lavoro che svolgi in questi callback sia limitato all'esecuzione di operazioni che comportano un aggiornamento effettivo dell'interfaccia utente. Qualsiasi altro lavoro che non tocca il DOM o aggiorna gli stili ritarderà inutilmente il rendering del frame successivo, quindi fai attenzione.

Conclusione

I dati sul campo sono la migliore fonte di informazioni a cui puoi attingere per capire quali interazioni sono problematiche per gli utenti reali sul campo. Se ti affidi a strumenti di raccolta dei dati sul campo come la libreria JavaScript web-vitals (o un fornitore RUM), puoi avere maggiore certezza di quali interazioni sono più problematiche, per poi passare alla riproduzione delle interazioni problematiche in laboratorio e alla loro correzione.

Immagine hero di Unsplash, di Federico Respini.