Scopri come trovare interazioni lente nei dati sul campo del tuo sito web per trovare opportunità di miglioramento dell'Interaction to Next Paint.
I dati sul campo indicano in che modo gli utenti reali utilizzano il tuo sito web. Mette in evidenza i problemi che non riesci a 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 vitali per aiutarti a correggerle.
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 ha problemi di INP. Successivamente, scoprirai come utilizzare la compilazione dell'attribuzione della libreria JavaScript web-vitals e le nuove informazioni fornite dall'API Long Animation Frames (LoAF) per raccogliere e interpretare i dati sul campo per le 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 dati sul campo da utenti reali di Chrome che hanno attivato l'invio di dati di telemetria.
I dati di CrUX vengono visualizzati in diverse aree e dipendono dall'ambito delle informazioni che stai cercando. CrUX può fornire dati su INP e su altre metriche di Core Web Vitals per:
- Singole pagine e intere origini utilizzando PageSpeed Insights.
- Tipi di pagine. Ad esempio, molti siti web di e-commerce hanno tipi di pagine come Pagina dei dettagli del prodotto e Pagina della scheda di prodotto. Puoi ottenere i dati di CrUX per tipi di pagina 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 di campo corrispondenti, se disponibili, verranno visualizzati per più metriche, tra cui l'INP. Puoi anche utilizzare i pulsanti di attivazione/disattivazione per controllare i valori INP per le dimensioni mobile e desktop.
Questi dati sono utili perché ti indicano se hai un problema. Tuttavia, CrUX non è in grado di dirti cosa causa i problemi. Esistono molte soluzioni di monitoraggio degli utenti reali (RUM) che ti aiuteranno a raccogliere i tuoi dati dei campi dagli utenti del tuo sito web per rispondere a questa domanda. Una possibilità è raccogliere autonomamente i dati dei campi utilizzando la libreria JavaScript web-vitals.
Raccogli i dati dei campi con la libreria JavaScript web-vitals
La web-vitals
libreria JavaScript è uno script che puoi caricare sul tuo sito web per raccogliere i dati sul campo dagli utenti del tuo sito web. Puoi utilizzarlo per registrare una serie di metriche, tra cui l'INP nei browser che lo supportano.
La versione 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 sul campo degli utenti, devi inviarli da qualche parte:
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 indicano molto di più di quanto farebbe CrUX. È qui che entra in gioco la compilazione dell'attribuzione della libreria web-vitals.
Scopri di più sulla compilazione dell'attribuzione della libreria web-vitals
La costruzione dell'attribuzione della libreria web-vitals mostra dati aggiuntivi che puoi ottenere dagli utenti sul campo per aiutarti a risolvere meglio i problemi relativi alle interazioni 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
});
Oltre all'IPN della pagina stessa, la compilazione dell'attribuzione fornisce molti dati che puoi utilizzare per comprendere i motivi delle interazioni lente, inclusa la parte dell'interazione su cui concentrarti. Può aiutarti a rispondere a domande importanti come:
- "L'utente ha interagito con la pagina durante il caricamento?"
- "I gestori di eventi dell'interazione sono stati eseguiti per molto tempo?"
- "Il codice del gestore di eventi di interazione è stato ritardato dall'inizio? Se sì, cosa altro stava succedendo nel thread principale in quel momento?"
- "L'interazione ha causato un sacco di lavoro di rendering che ha ritardato la visualizzazione del fotogramma successivo?"
La seguente tabella mostra alcuni dei dati di attribuzione di base che puoi ottenere dalla libreria, utili per individuare alcune cause importanti delle interazioni lente sul tuo sito web:
Chiave dell'oggetto attribution
|
Dati |
---|---|
interactionTarget
|
Un selettore CSS che rimanda all'elemento che ha generato il valore INP della pagina, ad esempio button#save .
|
interactionType
|
Il tipo di interazione, da clic, tocchi o input da tastiera. |
inputDelay *
|
Il ritardo di input dell'interazione. |
processingDuration *
|
Il tempo che intercorre tra l'inizio dell'esecuzione del primo gestore di eventi in risposta all'interazione dell'utente e il termine dell'elaborazione di tutti i gestori di eventi. |
presentationDelay *
|
Il ritardo di visualizzazione dell'interazione, che si verifica dal termine dei gestori degli eventi fino al momento in cui viene visualizzato il frame successivo. |
longAnimationFrameEntries *
|
Le voci del LoAF associate all'interazione. Per ulteriori informazioni, consulta la sezione successiva. |
A partire dalla versione 4 della libreria web-vitals, puoi ottenere informazioni ancora più approfondite sulle interazioni problematiche tramite i 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).
L'API Long Animation Frames (LoAF)
Il debug delle interazioni che utilizzano i dati dei campi è un'attività complessa. Tuttavia, con i dati di LoAF ora è possibile ottenere informazioni più dettagliate sulle cause delle interazioni lente, poiché LoAF espone una serie di tempistiche dettagliate e altri dati che puoi utilizzare per individuare cause precise e, soprattutto, dove si trova l'origine del problema nel codice del tuo sito web.
La compilazione dell'attribuzione della libreria web-vitals espone un array di voci LoAF sotto la chiave longAnimationFrameEntries
dell'oggetto attribution
. La tabella seguente elenca alcuni dati chiave che puoi trovare in ogni voce LoAF:
Chiave oggetto voce LoAF | Dati |
---|---|
duration
|
La durata del frame dell'animazione lungo fino al termine del layout, esclusi la pittura e la composizione. |
blockingDuration
|
La durata totale del frame in cui il browser non è stato in grado di rispondere rapidamente a causa di attività lunghe. Questo tempo di blocco può includere attività lunghe che eseguono JavaScript, nonché eventuali attività di rendering lunghe successive nel frame. |
firstUIEventTimestamp
|
Timestamp di quando l'evento è stato in coda durante il frame. Utile per capire l'inizio del ritardo di input di un'interazione. |
startTime
|
Il timestamp di inizio dell'inquadratura. |
renderStart
|
Quando è iniziato il rendering del frame. Sono inclusi eventuali callback requestAnimationFrame (e callback ResizeObserver , se applicabili), ma potenzialmente prima dell'inizio di qualsiasi lavoro di stile/layout.
|
styleAndLayoutStart
|
Quando vengono eseguite operazioni di stile/layout nel frame. Può essere utile per capire la durata del lavoro di stile/layout se si considerano altri timestamp disponibili. |
scripts
|
Un array di elementi contenenti informazioni sull'attribuzione dello script che contribuiscono all'INP della pagina. |
Tutte queste informazioni possono darti molte informazioni su cosa rende lenta un'interazione, ma l'array scripts
visualizzato dalle voci LoAF dovrebbe essere di particolare interesse:
Chiave oggetto attribuzione script | Dati |
---|---|
invoker
|
L'invocatore. Questo può variare in base al tipo di invocatore descritto nella riga successiva. Esempi di invocatori possono essere valori come 'IMG#id.onload' , 'Window.requestAnimationFrame' o 'Response.json.then' . |
invokerType
|
Il tipo di invocatore. Può essere 'user-callback' , 'event-listener' , 'resolve-promise' , 'reject-promise' , 'classic-script' o 'module-script' .
|
sourceURL
|
L'URL dello script da cui ha avuto origine il frame dell'animazione lungo. |
sourceCharPosition
|
La posizione del carattere nello script identificata 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 sulla sua responsabilità.
Misurare e identificare le cause comuni delle interazioni lente
Per darti un'idea di come potresti utilizzare queste informazioni, questa guida ti spiegherà come utilizzare i dati LoAF visualizzati nella libreria web-vitals
per determinare alcune cause 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 degli eventi registrati dell'interazione e di qualsiasi altro evento intermedio. Le durate di elaborazione elevate vengono indicate nella libreria Webvitals:
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 che il codice del gestore degli eventi ha impiegato troppo tempo per essere eseguito, ma non è sempre così. Una volta confermato che si tratta del problema, puoi approfondire con 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.sort((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 risalire alla causa esatta 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 degli eventi a lungo termine.
- Il nome della funzione.
Questo tipo di dati è inestimabile. Non dovrai più fare la fatica di scoprire esattamente quale interazione o quale dei relativi gestori eventi era responsabile di valori elevati della durata dell'elaborazione. Inoltre, poiché gli script di terze parti possono spesso registrare i propri gestori eventi, puoi determinare se il problema è causato o meno dal tuo codice. Per il codice di cui hai il controllo, ti consigliamo di consultare la sezione relativa all'ottimizzazione delle attività lunghe.
Ritardi di input lunghi
Sebbene i gestori di eventi a lungo termine siano comuni, ci sono altre parti dell'interazione da considerare. Una parte si verifica prima della durata dell'elaborazione, nota come ritardo dell'input. Si tratta del tempo che intercorre tra il momento in cui l'utente avvia l'interazione e il momento in cui iniziano a essere eseguiti i relativi callback del gestore eventi. Si verifica quando il thread principale sta già elaborando un'altra attività. La build dell'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 inserimento elevati, devi capire cosa stava succedendo nella pagina al momento dell'interazione che ha causato il lungo ritardo di inserimento. Spesso si tratta di capire se l'interazione si è verificata durante il caricamento della pagina o dopo.
Si è verificato durante il caricamento della pagina?
Il thread principale è spesso più impegnato durante il caricamento di una pagina. Durante questo periodo, vengono messe in coda ed elaborate varie attività e, se l'utente tenta di interagire con la pagina mentre vengono eseguite, l'interazione può essere ritardata. Le pagine che caricano molto codice JavaScript possono avviare il lavoro di compilazione e valutazione degli script, nonché eseguire funzioni che preparano una pagina per le interazioni degli utenti. Questo lavoro può essere d'intralcio se l'utente interagisce mentre si verifica questa attività e tu puoi scoprire se questo è il caso degli 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.sort((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 sul campo e noti ritardi di input elevati e tipi di invocatore 'classic-script'
o 'module-script'
, è lecito affermare che gli script sul tuo sito richiedono molto tempo per la valutazione e bloccano il thread principale per un tempo sufficiente a ritardare le interazioni. Puoi ridurre questo tempo di blocco suddividendo gli script in bundle più piccoli, rimandando il caricamento del codice inizialmente inutilizzato a un momento successivo e controllando il tuo sito per rilevare il codice inutilizzato che puoi rimuovere del tutto.
È successo 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 inserimento dopo il caricamento della pagina possono essere il codice che viene eseguito periodicamente a causa di una chiamata setInterval
precedente o anche i richiami di eventi che sono stati messi in coda per essere eseguiti in precedenza e sono 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.sort((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 per la risoluzione dei problemi relativi ai valori elevati della durata dell'elaborazione, i ritardi di inserimento elevati dovuti alle cause sopra indicate ti forniranno dati dettagliati sull'attribuzione dello script. Ciò che cambia, però, è che il tipo di invocatore cambia in base alla natura del lavoro che ha ritardato l'interazione:
'user-callback'
indica che l'attività di blocco proveniva dasetInterval
,setTimeout
o persino darequestAnimationFrame
.'event-listener'
indica che l'attività di blocco proviene da un input precedente inserito in coda e ancora in fase di elaborazione.'resolve-promise'
e'reject-promise'
indicano che l'attività di blocco proveniva da un lavoro asincrono avviato in precedenza e risolto o rifiutato in un 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 inserimento è dovuto al tuo codice o a quello di uno script di terze parti.
Ritardi lunghi nella presentazione
I ritardi nella presentazione corrispondono all'ultimo chilometro di un'interazione e iniziano quando i gestori di eventi dell'interazione terminano, fino al punto in cui è stato visualizzato 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ò indicare la durata del ritardo di visualizzazione 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 elevati nella presentazione delle interazioni che contribuiscono all'INP del tuo sito web, le cause possono variare, ma di seguito ci sono un paio di cause da tenere in considerazione.
Lavoro di stile e layout costosi
I lunghi ritardi nella presentazione possono comportare costosi lavori di ricalcolo dello stile e layout che derivano da una serie di cause, tra cui selettori CSS complessi e dimensioni del DOM di grandi dimensioni. 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.sort((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 dice la durata del lavoro di stile e layout per un frame, ma ti dice quando è iniziato. Con questo timestamp di inizio, puoi utilizzare altri dati di LoAF per calcolare una durata accurata del lavoro determinando l'ora di fine dell'inquadratura e sottraendo il timestamp di inizio del lavoro di stile e layout.
Callback requestAnimationFrame
a lunga esecuzione
Una potenziale causa di lunghi ritardi nella presentazione è un eccessivo lavoro svolto in un callback di requestAnimationFrame
. I contenuti di questo callback vengono eseguiti al termine dell'esecuzione dei gestori degli eventi, ma appena prima del ricomputo degli stili e del lavoro di layout.
Questi callback possono richiedere molto tempo per essere completati se il lavoro svolto al loro interno è complesso. Se sospetti che i valori elevati del ritardo di visualizzazione 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.sort((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 requestAnimationFrame
callback, assicurati che le operazioni che stai eseguendo in questi callback siano limitate a quelle che generano un aggiornamento effettivo dell'interfaccia utente. Qualsiasi altro lavoro che non tocca il DOM o aggiorna gli stili ritarda inutilmente la colorazione del frame successivo, quindi fai attenzione.
Conclusione
I dati sul campo sono la migliore fonte di informazioni a cui puoi fare riferimento per capire quali interazioni sono problematiche per gli utenti reali sul campo. Se utilizzi strumenti di raccolta dei dati sul campo come la libreria JavaScript web-vitals (o un provider RUM), puoi avere maggiori informazioni sulle interazioni più problematiche e passare alla riproduzione delle interazioni problematiche in laboratorio per poi correggerle.
Immagine hero di Unsplash, di Federico Respini.