Scopri come trovare interazioni lente nei dati dei campi del tuo sito web in modo da poter trovare opportunità per migliorare l'interazione con Next Paint.
I dati sul campo sono dati che indicano in che modo gli utenti effettivi utilizzano il tuo sito web. Prevede problemi che non sono presenti solo nei dati del lab. Per quanto riguarda l'interazione con 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 imparerai a valutare rapidamente il valore INP del tuo sito web utilizzando i dati sul campo del Report sull'esperienza utente di Chrome (CrUX) per vedere se il tuo sito web presenta problemi con INP. Successivamente, imparerai a utilizzare la build dell'attribuzione della libreria JavaScript delle vitali web (e le nuove informazioni che fornisce dall'API Long Animation Frames (LoAF)) per raccogliere e interpretare i dati dei campi 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 altri Core Web Vitals per:
- Singole pagine e intere origini utilizzando PageSpeed Insights.
- Tipi di pagine. Ad esempio, molti siti web di e-commerce dispongono di tipi di pagina dei dettagli del prodotto e pagina scheda di prodotto. Puoi ottenere i dati di CrUX per tipi di pagina unici in Search Console.
Per iniziare, puoi inserire l'URL del tuo sito web in PageSpeed Insights. Una volta inserito l'URL, i relativi dati dei campi, se disponibili, verranno visualizzati per più metriche, tra cui INP. Puoi anche utilizzare i pulsanti di attivazione/disattivazione per verificare i valori INP per le dimensioni per dispositivi mobili e computer.
Questi dati sono utili perché indicano se hai un problema. Ciò che CrUX non può fare, tuttavia, è indicare cosa sta causando i problemi. Sono disponibili molte soluzioni RUM (Real User Monitoring) che ti aiuteranno a raccogliere i dati dei campi dagli utenti del tuo sito web per poter rispondere a questa domanda. Un'opzione è raccogliere personalmente i dati dei campi utilizzando la libreria JavaScript delle vitali web.
Raccogli 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 dagli utenti del sito web. Puoi utilizzarlo per registrare una serie di metriche, tra cui INP nei browser che la supportano.
La build standard della libreria di dati web 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 forniti dagli utenti, è consigliabile inviarli a una delle seguenti posizioni:
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 forniscono molto di più di quanto farebbe CrUX. È qui che entra in gioco l'attribuzione build della libreria di Web-vitals.
Vai oltre con lo sviluppo dell'attribuzione della libreria di vitali web
La generazione dell'attribuzione della libreria di dati web mostra dati aggiuntivi che puoi ricevere dagli utenti sul campo per aiutarti a risolvere meglio i problemi relativi alle interazioni problematiche che interessano l'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'INP della pagina, la build dell'attribuzione fornisce molti dati che puoi utilizzare per capire i motivi delle interazioni lente, inclusa la parte dell'interazione su cui concentrarti. Può aiutarti a rispondere a domande importanti quali:
- "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? In tal caso, che cos'altro stava accadendo nel thread principale in quel momento?"
- "L'interazione ha causato un eccessivo lavoro di rendering che ha ritardato la colorazione del frame 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 oggetto attribution
|
Dati |
---|---|
interactionTarget
|
Un selettore CSS che punta all'elemento che ha generato il valore INP della pagina, ad esempio button#save .
|
interactionType
|
Il tipo di interazione, derivante da clic, tocchi o input da tastiera. |
inputDelay *
|
Il ritardo di input dell'interazione. |
processingDuration *
|
Il tempo che intercorre dall'inizio dell'esecuzione del primo listener di eventi in risposta all'interazione dell'utente fino al termine dell'elaborazione di tutti i listener di eventi. |
presentationDelay *
|
Il ritardo nella presentazione dell'interazione, che si verifica a partire dal momento in cui i gestori di eventi terminano fino al momento in cui viene visualizzato il frame successivo. |
longAnimationFrameEntries *
|
Voci dal LoAF associate all'interazione. Per ulteriori informazioni, leggi la sezione che segue. |
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 dell'input, durata dell'elaborazione e ritardo nella presentazione) e l'API Long Animation Frames (LoAF).
API Long Animation Frames (LoAF)
Il debug delle interazioni mediante dati sul campo è un compito impegnativo. Con i dati provenienti da LoAF, tuttavia, è ora possibile ottenere informazioni migliori sulle cause alla base delle interazioni lente, poiché LoAF espone una serie di tempistiche dettagliate e altri dati che possono essere utilizzati per individuare le cause precise e, soprattutto, dove l'origine del problema è nel codice del tuo sito web.
La build di attribuzione della libreria web-vitals mostra un array di voci LoAF sotto la chiave longAnimationFrameEntries
dell'oggetto attribution
. La seguente tabella elenca alcuni bit chiave di dati 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 quantità di tempo totale all'interno 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é qualsiasi attività di rendering lunga successiva all'interno del 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 iniziale del frame. |
renderStart
|
L'inizio del lavoro di rendering per il frame. Sono inclusi i callback requestAnimationFrame (e i callback ResizeObserver , se applicabili), ma potenzialmente prima dell'inizio del lavoro di stile/layout.
|
styleAndLayoutStart
|
Quando si verificano lavori di stile e layout all'interno del frame. Può essere utile per capire la lunghezza del lavoro di stile/layout quando si individuano altri timestamp disponibili. |
scripts
|
Un array di elementi contenenti informazioni sull'attribuzione degli 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. Può variare in base al tipo di callback descritto nella riga successiva. Esempi di richiamatori 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 identificato da sourceURL .
|
sourceFunctionName
|
Il nome della funzione nello script identificato. |
Ogni voce in questo array contiene i dati mostrati nella tabella, che fornisce informazioni sullo script responsabile dell'interazione lenta e sui relativi motivi.
Misurare e identificare le cause comuni alla base 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.
Lunghe tempi di elaborazione
La durata di elaborazione di un'interazione è il tempo necessario per l'esecuzione fino al completamento dei callback del gestore di eventi registrati dell'interazione e di tutto ciò che potrebbe verificarsi nel mezzo. 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 l'esecuzione del codice del gestore di eventi richieda troppo tempo, ma non è sempre così. Dopo aver confermato che il problema è questo, puoi approfondire 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 lavorare con i dati LoAF per individuare la causa precisa alla base di un'interazione con valori di durata di elaborazione elevata, tra cui:
- L'elemento e il relativo listener di eventi registrato.
- Il file dello script e la posizione del carattere al suo interno, contenente il codice del gestore di eventi a lunga esecuzione.
- Il nome della funzione.
Questo tipo di dati è inestimabile. Non dovrai più preoccuparti di scoprire esattamente quale interazione, o quale dei suoi gestori di eventi, era responsabile di valori di durata di elaborazione elevati. Inoltre, poiché spesso gli script di terze parti possono registrare i propri gestori di eventi, puoi determinare se il responsabile è stato il tuo codice. Per il codice su cui hai il controllo, ti consigliamo di dare un'occhiata all'ottimizzazione delle attività lunghe.
Ritardi lunghi nell'input
Sebbene i gestori di eventi a lunga durata 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 l'avvio dell'interazione da parte dell'utente e il momento in cui iniziano a essere eseguiti i callback del gestore di eventi e si verificano 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 presentano ritardi di input elevati, devi capire cosa stava accadendo sulla pagina al momento dell'interazione che ha causato il lungo ritardo di input. Ciò spesso si riduce al fatto che l'interazione si sia verificata durante il caricamento della pagina o successivamente.
Si è verificato durante il caricamento della pagina?
Il thread principale è spesso più occupato durante il caricamento di una pagina. Durante questo periodo, tutti i tipi di attività vengono messi in coda ed elaborati e, se l'utente tenta di interagire con la pagina mentre è tutto in corso, l'interazione potrebbe essere ritardata. Le pagine che caricano molto JavaScript possono iniziare a compilare e valutare gli script, nonché a 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 nell'input e tipi di callback elevati di 'classic-script'
o 'module-script'
, è corretto dire che la valutazione degli script sul tuo sito richiede molto tempo e bloccano il thread principale abbastanza a lungo da ritardare le interazioni. Puoi ridurre il tempo di blocco suddividendo gli script in pacchetti più piccoli, rimandare il caricamento del codice inizialmente inutilizzato in un secondo momento e verificare se nel tuo sito è presente codice inutilizzato da rimuovere completamente.
Dopo il caricamento della pagina?
Sebbene spesso si verifichino ritardi durante il caricamento di una pagina, è possibile che si verifichino dopo il caricamento di una pagina, per una causa completamente diversa. Le cause comuni dei ritardi nell'inserimento dopo il caricamento pagina possono essere il codice che viene eseguito periodicamente a causa di una chiamata setInterval
precedente o persino i callback di eventi che erano ancora in coda per l'esecuzione 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 nel caso della risoluzione dei problemi con valori elevati di durata di elaborazione, elevati ritardi nell'inserimento dovuti alle cause menzionate in precedenza ti forniranno dati dettagliati di attribuzione degli script. La differenza, tuttavia, è 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 in coda e ancora in elaborazione.'resolve-promise'
e'reject-promise'
indicano che l'attività di blocco deriva da un lavoro asincrono avviato in precedenza e risolto o rifiutato 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 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 l'opera in un gestore di eventi dovuto a un'interazione modifica lo stato visivo dell'interfaccia utente. Come per le durate di elaborazione e i ritardi degli input, la libreria delle vital web può indicare 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 elevati nella presentazione delle interazioni che contribuiscono all'INP del tuo sito web, le cause possono variare; tuttavia, ecco 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 raccolta delle vitals del web:
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 indicherà la durata dello stile e del layout per un frame, ma ti dirà quando è stato avviato. Con questo timestamp iniziale, puoi utilizzare altri dati di LoAF per calcolare una durata accurata dell'attività determinando l'ora di fine del frame e sottraendo da quest'ultima il timestamp di inizio dello stile e del layout.
Callback requestAnimationFrame
di lunga durata
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 di eventi, ma appena prima delle operazioni di ricalcolo dello stile e layout.
Questi callback possono richiedere molto tempo se il lavoro svolto al loro interno è complesso. Se sospetti che i valori di ritardo della presentazione elevati siano dovuti al lavoro che stai svolgendo con requestAnimationFrame
, puoi utilizzare i dati LoAF visualizzati nella libreria delle vital web 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 callback requestAnimationFrame
, assicurati che il lavoro che stai svolgendo in questi callback sia limitato all'esecuzione di operazioni che si traducono in 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 attingere per capire quali interazioni sono problematiche per gli utenti effettivi sul campo. Affidandoti a strumenti di raccolta dei dati sul campo come la libreria JavaScript delle funzionalità web (o un provider RUM), puoi essere più sicuro di quali interazioni sono più problematiche, quindi puoi passare alla riproduzione di interazioni problematiche nel lab per poi correggerle.
Immagine hero da Unsplash, di Federico Respini.