API User Timing

Informazioni sulla tua app web

Alex Danilo

Le applicazioni web ad alte prestazioni sono fondamentali per un'esperienza utente ottimale. Man mano che le applicazioni web diventano sempre più complesse, è fondamentale comprendere l'impatto sulle prestazioni per creare un'esperienza coinvolgente. Negli ultimi anni, nel browser sono state visualizzate diverse API per contribuire ad analizzare il rendimento della rete, i tempi di caricamento e così via, ma queste non forniscono necessariamente dettagli granulari con flessibilità sufficiente per trovare ciò che rallenta l'applicazione. Inserisci l'API User Timing, che fornisce un meccanismo che puoi utilizzare per analizzare la tua applicazione web e identificare dove la tua applicazione impiega il tempo. In questo articolo illustreremo l'API e alcuni esempi di utilizzo.

Non puoi ottimizzare ciò che non misuri

Il primo passaggio per velocizzare un'applicazione web lenta consiste nell'individuare dove viene speso il tempo. Misurare l'impatto in termini di tempo delle aree di codice JavaScript è il modo ideale per identificare gli hot spot, il primo passo per scoprire come migliorare il rendimento. Fortunatamente, l'API User Timing ti consente di inserire chiamate API in parti diverse del codice JavaScript ed estrarre dati di temporizzazione dettagliati che possono essere utilizzati per aiutarti a ottimizzare.

Tempo ad alta risoluzione e now()

Un aspetto fondamentale per una misurazione accurata del tempo è la precisione. In passato, i tempi erano basati sulla misurazione in millisecondi, il che va bene, ma per creare un sito a 60 FPS senza scatti, ogni frame deve essere disegnato in 16 ms. Pertanto, se hai una precisione solo a millisecondi, manca la precisione necessaria per un'analisi efficace. Inserisci Tempo ad alta risoluzione, un nuovo tipo di temporizzazione integrato nei browser moderni. La funzionalità Tempo ad alta risoluzione ci fornisce indicatori di data e ora con virgola mobile che possono essere precisi fino a una risoluzione di microsecondi, mille volte meglio di prima.

Per ottenere l'ora corrente nella tua applicazione web, chiama il metodo now() che forma un'estensione dell'interfaccia Performance. Il seguente codice mostra come procedere:

var myTime = window.performance.now();

Esiste un'altra interfaccia chiamata PerformanceTiming che fornisce una serie di tempi diversi relativi al caricamento dell'applicazione web. Il metodo now() restituisce il tempo trascorso dall'ora navigationStart in PerformanceTiming.

Il tipo DOMHighResTimeStamp

In passato, per misurare il tempo delle applicazioni web si utilizzava qualcosa come Date.now(), che restituisce un DOMTimeStamp. DOMTimeStamp restituisce un numero intero di millisecondi come valore. Per fornire la maggiore precisione necessaria per il tempo ad alta risoluzione, è stato introdotto un nuovo tipo denominato DOMHighResTimeStamp. Questo tipo è un valore con virgola mobile che restituisce anche il tempo in millisecondi. Tuttavia, poiché è con virgola mobile, il valore può rappresentare millisecondi frazionari e quindi può fornire una precisione di un millesimo di millisecondo.

Interfaccia di misurazione dei tempi utente

Ora che abbiamo timestamp ad alta risoluzione, utilizziamo l'interfaccia Tempi dell'utente per estrarre le informazioni sui tempi.

L'interfaccia User Timing fornisce funzioni che ci consentono di chiamare metodi in punti diversi della nostra applicazione, che possono fornire un percorso di breadcrumb in stile Hansel e Gretel per consentirci di monitorare dove viene speso il tempo.

In uso: mark()

Il metodo mark() è lo strumento principale del nostro kit di strumenti per l'analisi dei tempi. mark() memorizza un timestamp per noi. La cosa molto utile di mark() è che possiamo assegnare un nome al timestamp e l'API memorizzerà il nome e il timestamp come una singola unità.

Chiamare mark() in vari punti dell'applicazione ti consente di calcolare il tempo necessario per raggiungere quel "punto" nella tua applicazione web.

La specifica indica una serie di nomi suggeriti per i marchi che potrebbero essere interessanti e sono abbastanza autoesplicativi, come mark_fully_loaded, mark_fully_visible,mark_above_the_fold e così via.

Ad esempio, potremmo impostare un indicatore per quando l'applicazione è completamente caricata utilizzando il seguente codice:

window.performance.mark('mark_fully_loaded');

Impostando indicatori con nome in tutta la nostra applicazione web, possiamo raccogliere una serie di dati sui tempi e analizzarli a nostro piacimento per capire cosa fa l'applicazione e quando.

Calcolo delle misurazioni con measure()

Dopo aver impostato una serie di indicatori di tempo, devi scoprire il tempo trascorso tra un indicatore e l'altro. A questo scopo, utilizzi il metodo measure().

Il metodo measure() calcola il tempo trascorso tra i vari indicatori e può anche misurare il tempo tra un indicatore e uno dei nomi di eventi noti nell'interfaccia PerformanceTiming.

Ad esempio, puoi calcolare il tempo che intercorre tra il completamento del DOM e il caricamento completo dello stato dell'applicazione utilizzando il seguente codice:

window.performance.measure('measure_load_from_dom', 'domComplete', 'mark_fully_loaded');

Quando chiami measure(), il risultato viene memorizzato indipendentemente dai segni impostati, in modo da poterli recuperare in un secondo momento. Se memorizzi i tempi di attesa durante l'esecuzione dell'applicazione, questa rimane reattiva e puoi scaricare tutti i dati dopo che l'applicazione ha completato un lavoro in modo che possano essere analizzati in un secondo momento.

Eliminare i segni con clearMarks()

A volte è utile poter eliminare una serie di indicatori che hai configurato. Ad esempio, potresti eseguire esecuzioni collettive sulla tua applicazione web e quindi vuoi iniziare da capo ogni esecuzione.

È abbastanza facile eliminare i segni che hai configurato chiamando clearMarks().

Pertanto, il codice di esempio riportato di seguito eliminerà tutti i segni esistenti, in modo da poter configurare di nuovo un'esecuzione del tempo, se vuoi.

window.performance.clearMarks();

Naturalmente, in alcuni casi potresti non voler cancellare tutti i segni. Pertanto, se vuoi eliminare segni specifici, puoi semplicemente passare il nome del segno da rimuovere. Ad esempio, il codice riportato di seguito:

window.performance.clearMarks('mark_fully_loaded');

elimina l'indicatore impostato nel primo esempio, lasciando invariati gli altri indicatori impostati.

Potresti anche voler eliminare le misure che hai creato e per farlo esiste un metodo corrispondente chiamato clearMeasures(). Funziona esattamente come clearMarks(), ma agisce sulle misurazioni che hai effettuato. Ad esempio, il codice:

window.performance.clearMeasures('measure_load_from_dom');

rimuoverà la misura che abbiamo creato nell'esempio measure() riportato sopra. Se vuoi rimuovere tutte le misure, funziona come clearMarks(), in quanto devi solo chiamare clearMeasures() senza argomenti.

Estrazione dei dati relativi ai tempi

È bene impostare indicatori e misurare gli intervalli, ma a un certo punto è necessario accedere ai dati relativi ai tempi per eseguire alcune analisi. Anche questo è molto semplice, devi solo utilizzare l'interfaccia PerformanceTimeline.

Ad esempio, il metodo getEntriesByType() ci consente di ottenere tutti i tempi di marcatura o tutti i tempi di misurazione sotto forma di elenco, in modo da poterli analizzare e interpretare. La cosa bella è che l'elenco viene restituito in ordine cronologico, quindi puoi vedere i segni nell'ordine in cui sono stati raggiunti nella tua applicazione web.

Il codice riportato di seguito:

var items = window.performance.getEntriesByType('mark');

restituisce un elenco di tutti i markup che sono stati raggiunti nella nostra applicazione web, mentre il codice:

var items = window.performance.getEntriesByType('measure');

restituisce un elenco di tutte le misure che abbiamo effettuato.

Puoi anche recuperare un elenco di voci utilizzando il nome specifico che hai assegnato. Ad esempio, il codice:

var items = window.performance.getEntriesByName('mark_fully_loaded');

ci restituirà un elenco contenente un elemento con il timestamp "mark_fully_loaded" nella proprietà startTime.

Temporizzazione di una richiesta XHR (esempio)

Ora che abbiamo un quadro abbastanza chiaro dell'API User Timing, possiamo utilizzarla per analizzare il tempo necessario per l'esecuzione di tutti i nostri XMLHttpRequests nella nostra applicazione web.

Innanzitutto, modificheremo tutte le richieste send() in modo da emettere una chiamata di funzione che configuri gli indicatori e, contemporaneamente, cambieremo i nostri callback di successo con una chiamata di funzione che imposta un altro indicatore e genera una misura del tempo impiegato dalla richiesta.

Di solito, quindi, XMLHttpRequest avrà il seguente aspetto:

var myReq = new XMLHttpRequest();
myReq.open('GET', url, true);
myReq.onload = function(e) {
  do_something(e.responseText);
}
myReq.send();

Per il nostro esempio, aggiungeremo un contatore globale per monitorare il numero di richieste e utilizzarlo anche per memorizzare una misura per ogni richiesta effettuata. Il codice per eseguire questa operazione è il seguente:

var reqCnt = 0;

var myReq = new XMLHttpRequest();
myReq.open('GET', url, true);
myReq.onload = function(e) {
  window.performance.mark('mark_end_xhr');
  reqCnt++;
  window.performance.measure('measure_xhr_' + reqCnt, 'mark_start_xhr', 'mark_end_xhr');
  do_something(e.responseText);
}
window.performance.mark('mark_start_xhr');
myReq.send();

Il codice riportato sopra genera una misura con un valore del nome univoco per ogni XMLHttpRequest inviato. Supponiamo che le richieste vengano eseguite in sequenza. Il codice per le richieste parallele dovrebbe essere un po' più complesso per gestire le richieste che vengono restituite fuori ordine. Lasciamo questo esercizio al lettore.

Una volta che l'applicazione web ha effettuato una serie di richieste, potremmo scaricarle tutte nella console utilizzando il codice seguente:

var items = window.performance.getEntriesByType('measure');
for (var i = 0; i < items.length; ++i) {
  var req = items[i];
  console.log('XHR ' + req.name + ' took ' + req.duration + 'ms');
}

Conclusione

L'API User Timing ti offre molti strumenti utili da applicare a qualsiasi aspetto della tua applicazione web. È possibile restringere gli hotspot dell'applicazione inserendo chiamate API in tutta l'applicazione web e sottoponendo a post-elaborazione i dati sui tempi generati per creare un quadro chiaro di dove viene speso il tempo. Ma cosa succede se il tuo browser non supporta questa API? Nessun problema, qui puoi trovare un ottimo polyfill che emula molto bene l'API e funziona bene anche con webpagetest.org. Cosa stai aspettando? Prova subito l'API User Timing nelle tue applicazioni. Scoprirai come velocizzarle e i tuoi utenti ti ringrazieranno per aver migliorato così tanto la loro esperienza.