Metriche personalizzate

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 impiegato da un'app a pagina singola per passare da una "pagina" a un'altra.
  • 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, hanno dovuto 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

Supporto dei browser

  • 52
  • 79
  • 57
  • 11

Origine

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():

// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  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'});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

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.

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 (come Attività lunghe) non sono esposte tramite l'oggetto performance, ma solo attraverso 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'API di misurazione per uso generico per le metriche basate sul tempo. Consente di contrassegnare arbitrariamente i punti nel tempo e misurare la durata tra questi indicatori 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:

// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // 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});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

API Long Tasks

Supporto dei browser

  • 58
  • 79
  • x
  • x

Origine

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 verificare se quel codice blocca il thread principale. Infatti, 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:

// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // 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});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

API Element Timing

Supporto dei browser

  • 77
  • 79
  • x
  • x

Origine

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>
  // Catch errors since some browsers throw when using the new `type` option.
  // https://bugs.webkit.org/show_bug.cgi?id=209216
  try {
    // Create the performance observer.
    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});
  } catch (e) {
    // Do nothing if the browser doesn't support this API.
  }
</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:

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  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 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 time (ms): ${processingTime}`);
      console.log(`Total event duration (ms): ${duration}`);
      console.log(`Event type: ${eventType}`);
      console.log(target);
    });
  });

  // A durationThreshold of 16ms is necessary to surface more
  // interactions, since the default is 104ms. The minimum
  // durationThreshold is 16ms.
  po.observe({type: 'event', buffered: true, durationThreshold: 16});
} catch (error) {
  // Do nothing if the browser doesn't support this API.
}

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 chiamata fetch().
  • nextHopProtocol: protocollo utilizzato per recuperare la risorsa, ad esempio h2 o quic.
  • 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 valore encodedBodySize 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.

// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  const po = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      // If transferSize is 0, the resource was fulfilled via the cache.
      console.log(entry.name, entry.transferSize === 0);
    }
  });

  // Start listening for `resource` entries to be dispatched.
  po.observe({type: 'resource', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

Supporto dei browser

  • 57
  • 12
  • 58
  • 15

Origine

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.

// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  const po = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      // If transferSize is 0, the resource was fulfilled via the cache.
      console.log('Time to first byte', entry.responseStart);
    }
  });

  // Start listening for `navigation` entries to be dispatched.
  po.observe({type: 'navigation', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

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.

// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // 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});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

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.

// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // 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});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}