Le metriche incentrate sugli utenti sono molto preziose e puoi misurare universalmente su qualsiasi sito web. Queste metriche ti consentono di:
- Comprendere in che modo gli utenti reali interagiscono con il web nel suo complesso.
- Confronta il tuo sito con quello di un concorrente.
- Monitora i dati utili e strategici nei tuoi strumenti di analisi senza dover scrivere codice personalizzato.
Le metriche universali offrono una buona base di riferimento, ma in molti casi occorre misurare più semplicemente queste metriche per acquisire l'esperienza completa per il tuo sito specifico.
Le metriche personalizzate ti consentono di misurare aspetti dell'esperienza del tuo sito che possono essere applicati solo al tuo sito, ad esempio:
- Il tempo necessario per la transizione di un'app a pagina singola (APS) da una "pagina" a un altro.
- Tempo impiegato da una pagina per visualizzare i dati recuperati da un database per gli utenti che hanno eseguito l'accesso.
- Tempo impiegato da un'app con rendering lato server (SSR) per l'hydration.
- La percentuale di successi della cache per le risorse caricate dai visitatori di ritorno.
- La latenza degli eventi di clic o tastiera in un gioco.
API per misurare metriche personalizzate
In passato, gli sviluppatori web non avevano molte API di basso livello per misurare il rendimento e, di conseguenza, dovevano ricorrere a compromissioni per valutare le prestazioni di un sito.
Ad esempio, è possibile determinare se il thread principale è bloccato a causa di attività JavaScript a lunga esecuzione eseguendo un ciclo requestAnimationFrame
e calcolando il delta tra ciascun frame. Se il delta è molto più lungo della frequenza fotogrammi del display, puoi segnalarlo come un'attività lunga. Tuttavia, questi attacchi sono sconsigliati perché influiscono effettivamente sulle prestazioni (ad esempio consumando la batteria).
La prima regola per una misurazione efficace del rendimento è assicurarsi che le tecniche di misurazione del rendimento non causino problemi di rendimento. Pertanto, per le metriche personalizzate che misuri sul tuo sito, ti consigliamo di utilizzare una delle seguenti API, se possibile.
API Performance Observer
L'API Performance Observer è il meccanismo che raccoglie e mostra i dati di tutte le altre API per le prestazioni discusse in questa pagina. Comprendere è fondamentale per ottenere dati di qualità.
Puoi utilizzare PerformanceObserver
per abbonarti passivamente agli eventi relativi al rendimento. In questo modo i callback API si attivano durante i periodi di inattività, il che significa che di solito non interferiranno con le prestazioni della pagina.
Per creare un PerformanceObserver
, passalo un callback da eseguire ogni volta che vengono inviate nuove voci relative alle prestazioni. Quindi indichi all'osservatore quali tipi di voci ascoltare utilizzando il metodo observe()
:
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
po.observe({type: 'some-entry-type'});
Le sezioni seguenti elencano tutti i vari tipi di voce disponibili per l'osservazione, ma nei browser più recenti è possibile controllare quali tipi di voce sono disponibili tramite la proprietà PerformanceObserver.supportedEntryTypes
statica.
Osserva le voci già verificate
Per impostazione predefinita, gli oggetti PerformanceObserver
possono osservare le voci solo man mano che si presentano. Ciò può causare problemi se vuoi eseguire il caricamento lento del codice per l'analisi delle prestazioni in modo da non bloccare le risorse con priorità più elevata.
Per ottenere le voci storiche (dopo che si sono verificate), imposta il flag buffered
su true
quando chiami observe()
. Il browser includerà le voci cronologiche del buffer di voci delle prestazioni la prima volta che viene chiamato il callback PerformanceObserver
, fino alla dimensione massima del buffer per quel tipo.
po.observe({
type: 'some-entry-type',
buffered: true,
});
API Performance legacy da evitare
Prima dell'API Performance Observer, gli sviluppatori potevano accedere alle voci relative alle prestazioni utilizzando i seguenti tre metodi definiti nell'oggetto performance
:
Anche se queste API sono ancora supportate, il loro utilizzo non è consigliato perché non consentono di ascoltare le nuove voci emesse. Inoltre, molte nuove API (ad esempio largest-contentful-paint
) non vengono esposte tramite l'oggetto performance
, ma solo tramite PerformanceObserver
.
A meno che tu non abbia specificamente bisogno di compatibilità con Internet Explorer, è meglio evitare questi metodi nel tuo codice e utilizzare PerformanceObserver
in futuro.
API User Timing
L'API User Timing è un'interfaccia l'API di misurazione per le metriche basate sul tempo. Consente di contrassegnare arbitrariamente i punti per poi misurare la durata tra questi segni in un secondo momento.
// Record the time immediately before running a task.
performance.mark('myTask:start');
await doMyTask();
// Record the time immediately after running a task.
performance.mark('myTask:end');
// Measure the delta between the start and end of the task
performance.measure('myTask', 'myTask:start', 'myTask:end');
Sebbene API come Date.now()
o performance.now()
offrano capacità simili, il vantaggio dell'utilizzo dell'API User Timing è che si integra bene con gli strumenti per le prestazioni. Ad esempio, Chrome DevTools mostra le misurazioni dei tempi utente nel riquadro Rendimento. Inoltre, molti provider di analisi tengono automaticamente traccia di tutte le misurazioni effettuate e inviano i dati sulla durata al loro backend di analisi.
Per generare report sulle misurazioni del tempo utente, puoi utilizzare PerformanceObserver e registrarti per osservare le voci di tipo measure
:
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
// Start listening for `measure` entries to be dispatched.
po.observe({type: 'measure', buffered: true});
API Long Tasks
L'API Long Tasks è utile per sapere quando il thread principale del browser è bloccato per un tempo sufficientemente lungo da influire sulla frequenza fotogrammi o sulla latenza dell'input. L'API segnalerà tutte le attività eseguite per più di 50 millisecondi.
Ogni volta che devi eseguire codice costoso o caricare ed eseguire script di grandi dimensioni, è utile controllare se quel codice blocca il thread principale. In effetti, molte metriche di livello superiore sono basate sull'API Long Tasks stessa (ad esempio Time to Interactive (TTI) e Total Block Time (TBT)).
Per determinare quando si verificano attività lunghe, puoi utilizzare PerformanceObserver e registrarti per osservare voci di tipo longtask
:
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
// Start listening for `longtask` entries to be dispatched.
po.observe({type: 'longtask', buffered: true});
API Long Animation Frames
L'API Long Animation Frames è una nuova iterazione dell'API Long Tasks che esamina i frame lunghi, anziché le attività lunghe, di oltre 50 millisecondi. Questo consente di risolvere alcuni problemi dell'API Long Tasks, tra cui una migliore attribuzione e un ambito più ampio di ritardi potenzialmente problematici.
Per determinare quando si verificano frame lunghi, puoi utilizzare PerformanceObserver ed eseguire la registrazione per osservare le voci di tipo long-animation-frame
:
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
// Start listening for `long-animation-frame` entries to be dispatched.
po.observe({type: 'long-animation-frame', buffered: true});
API Element Timing
La metrica Largest Contentful Paint (LCP) è utile per sapere quando l'immagine o il blocco di testo più grande è stato visualizzato sullo schermo, ma in alcuni casi vuoi misurare il tempo di rendering di un altro elemento.
In questi casi, utilizza l'API Element Timing. L'API LCP si basa sull'API Element Timing e aggiunge report automatici sull'elemento con contenuti più grande, ma puoi anche generare report su altri elementi aggiungendo esplicitamente l'attributo elementtiming
e registrando un PerformanceObserver per osservare il tipo di voce element
.
<img elementtiming="hero-image" />
<p elementtiming="important-paragraph">This is text I care about.</p>
<!-- ... -->
<script>
const po = new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
// Log the entry and all associated details.
console.log(entry.toJSON());
}
});
// Start listening for `element` entries to be dispatched.
po.observe({type: 'element', buffered: true});
</script>
API Event Timing
La metrica Interazione con Next Paint (INP) valuta la reattività generale della pagina osservando tutte le interazioni di clic, tocco e tastiera durante il ciclo di vita di una pagina. L'INP di una pagina è solitamente l'interazione il cui completamento ha richiesto più tempo, dal momento in cui l'utente ha avviato l'interazione al momento in cui il browser visualizza il frame successivo che mostra il risultato visivo dell'input dell'utente.
La metrica INP è resa possibile dall'API Event Timing. Questa API espone una serie di timestamp che si verificano durante il ciclo di vita degli eventi, tra cui:
startTime
: l'ora in cui il browser riceve l'evento.processingStart
: l'ora in cui il browser è in grado di iniziare a elaborare i gestori di eventi per l'evento.processingEnd
: data e ora in cui il browser termina l'esecuzione di tutto il codice sincrono avviato dai gestori di eventi per questo evento.duration
: il tempo (arrotondato a 8 millisecondi per motivi di sicurezza) tra il momento in cui il browser riceve l'evento e il momento in cui è in grado di visualizzare il frame successivo al termine dell'esecuzione di tutto il codice sincrono avviato dai gestori di eventi.
L'esempio seguente mostra come utilizzare questi valori per creare misurazioni personalizzate:
const po = new PerformanceObserver((entryList) => {
// Get the last interaction observed:
const entries = Array.from(entryList.getEntries()).forEach((entry) => {
// Get various bits of interaction data:
const inputDelay = entry.processingStart - entry.startTime;
const processingTime = entry.processingEnd - entry.processingStart;
const presentationDelay = entry.startTime + entry.duration - entry.processingEnd;
const duration = entry.duration;
const eventType = entry.name;
const target = entry.target || "(not set)"
console.log("----- INTERACTION -----");
console.log(`Input delay (ms): ${inputDelay}`);
console.log(`Event handler processing time (ms): ${processingTime}`);
console.log(`Presentation delay (ms): ${presentationDelay}`);
console.log(`Total event duration (ms): ${duration}`);
console.log(`Event type: ${eventType}`);
console.log(target);
});
});
// A durationThreshold of 16ms is necessary to include more
// interactions, since the default is 104ms. The minimum
// durationThreshold is 16ms.
po.observe({type: 'event', buffered: true, durationThreshold: 16});
API Resource Timing
L'API Resource Timing offre agli sviluppatori informazioni dettagliate su come sono state caricate le risorse per una determinata pagina. Nonostante il nome dell'API, le informazioni che fornisce non si limitano ai dati temporali (anche se ce ne sono innumerevoli). Altri dati a cui puoi accedere includono:
initiatorType
: modalità di recupero della risorsa, ad esempio da un tag<script>
o<link>
oppure da una chiamatafetch()
.nextHopProtocol
: protocollo utilizzato per recuperare la risorsa, ad esempioh2
oquic
.encodedBodySize
/decodedBodySize]: la dimensione della risorsa nel formato codificato o decodificato (rispettivamente)transferSize
: le dimensioni della risorsa che è stata effettivamente trasferita sulla rete. Quando le risorse vengono soddisfatte dalla cache, questo valore può essere molto inferiore al valoreencodedBodySize
e in alcuni casi può essere zero (se non è richiesta la riconvalida della cache).
Puoi utilizzare la proprietà transferSize
delle voci di temporizzazione delle risorse per misurare una metrica Percentuale di successi della cache o Dimensioni totali delle risorse memorizzate nella cache, che può essere utile per comprendere in che modo la strategia di memorizzazione nella cache delle risorse influisce sulle prestazioni dei visitatori abituali.
L'esempio seguente registra tutte le risorse richieste dalla pagina e indica se ogni risorsa è stata soddisfatta o meno dalla cache.
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// If transferSize is 0, the resource was fulfilled using the cache.
console.log(entry.name, entry.transferSize === 0);
}
});
// Start listening for `resource` entries to be dispatched.
po.observe({type: 'resource', buffered: true});
API Navigation Timing
L'API Navigation Timing è simile all'API Resource Timing, ma segnala solo le richieste di navigazione. Anche il tipo di voce navigation
è simile al tipo di voce resource
, ma contiene alcune informazioni aggiuntive specifiche solo per le richieste di navigazione (ad esempio quando vengono attivati gli eventi DOMContentLoaded
e load
).
Una metrica monitorata da molti sviluppatori per comprendere il tempo di risposta del server (Time to First Byte (TTFB)) è disponibile utilizzando l'API Navigation Timing, in particolare il timestamp responseStart
della voce.
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// If transferSize is 0, the resource was fulfilled using the cache.
console.log('Time to first byte', entry.responseStart);
}
});
// Start listening for `navigation` entries to be dispatched.
po.observe({type: 'navigation', buffered: true});
Un'altra metrica a cui gli sviluppatori che utilizzano il service worker potrebbero essere interessati è il tempo di avvio del service worker per le richieste di navigazione. Questa è la quantità di tempo impiegata dal browser per avviare il thread del service worker prima che possa iniziare a intercettare gli eventi di recupero.
Il tempo di avvio del service worker per una determinata richiesta di navigazione può essere determinato dal delta tra entry.responseStart
e entry.workerStart
.
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log('Service Worker startup time:',
entry.responseStart - entry.workerStart);
}
});
// Start listening for `navigation` entries to be dispatched.
po.observe({type: 'navigation', buffered: true});
API Server Timing
L'API Server Timing consente di passare dati di temporizzazione specifici per la richiesta dal server al browser tramite le intestazioni delle risposte. Ad esempio, puoi indicare il tempo necessario per cercare i dati in un database per una determinata richiesta, cosa che può essere utile per il debug dei problemi di prestazioni causati da lentezza del server.
Per gli sviluppatori che utilizzano provider di analisi di terze parti, l'API Server Timing è l'unico modo per correlare i dati sulle prestazioni del server con altre metriche aziendali che potrebbero essere misurate da questi strumenti di analisi.
Per specificare i dati relativi ai tempi del server nelle risposte, puoi utilizzare l'intestazione della risposta Server-Timing
. Ecco un esempio.
HTTP/1.1 200 OK
Server-Timing: miss, db;dur=53, app;dur=47.2
Poi, dalle tue pagine, puoi leggere questi dati su entrambe le voci resource
o navigation
delle API Resource Timing e Navigation Timing.
// Create the performance observer.
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Logs all server timing data for this response
console.log('Server Timing', entry.serverTiming);
}
});
// Start listening for `navigation` entries to be dispatched.
po.observe({type: 'navigation', buffered: true});