Come e perché abbiamo creato gli approfondimenti sulle prestazioni

In Chrome 102 noterai un nuovo riquadro sperimentale, Informazioni sulle prestazioni, in DevTools. In questo post parleremo non solo del motivo per cui abbiamo lavorato a un nuovo pannello, ma anche delle sfide tecniche che abbiamo dovuto affrontare e delle decisioni che abbiamo preso lungo il percorso.

ALT_TEXT_HERE

Perché creare un altro pannello?

Se non l'hai ancora visto, abbiamo pubblicato un video sul motivo per cui abbiamo creato il riquadro Approfondimenti sul rendimento e su come ottenere approfondimenti utili sul rendimento del tuo sito web.

Il pannello del rendimento esistente è un'ottima risorsa se vuoi visualizzare tutti i dati del tuo sito web in un unico posto, ma abbiamo ritenuto che potesse essere un po' eccessivo. Se non sei un esperto di prestazioni, è difficile sapere esattamente cosa cercare e quali parti della registrazione sono pertinenti.

Accedi al riquadro Approfondimenti, dove puoi ancora visualizzare una cronologia della traccia e analizzare i dati, ma anche ottenere un elenco pratico di ciò che DevTools considera i principali "approfondimenti" da approfondire. Approfondimenti identifica problemi come richieste di blocco del rendering, spostamenti del layout e attività lunghe, per citarne alcuni, che possono influire negativamente sulle prestazioni di caricamento delle pagine del tuo sito web e, in particolare, sui punteggi dei Segnali web essenziali (CWV) del tuo sito. Oltre a segnalare i problemi, Performance Insights ti fornirà suggerimenti pratici per migliorare i punteggi CWV e link a ulteriori risorse e documentazione.

Link per il feedback nel riquadro

Questo pannello è sperimentale e vogliamo ricevere il tuo feedback. Comunicaci se riscontri bug o se hai richieste di funzionalità che ritieni possano aiutarti a migliorare il rendimento del tuo sito.

Come abbiamo creato Performance Insights

Come il resto di DevTools, abbiamo creato Performance Insights in TypeScript e abbiamo utilizzato componenti web, supportati da lit-html, per creare l'interfaccia utente. La differenza di Performance Insights è che l'interfaccia utente principale è un elemento HTML canvas e la sequenza temporale viene disegnata su questo canvas. Gran parte della complessità deriva dalla gestione di questa tela: non solo disegnare i dettagli giusti nel posto giusto, ma anche gestire gli eventi del mouse (ad esempio, dove ha fatto clic l'utente sulla tela? Hanno fatto clic su un evento che abbiamo disegnato?) e assicurarsi che il canvas venga eseguito nuovamente in modo efficace.

Più tracce su un'unica tela

Per un determinato sito web, esistono più "tracce" che vogliamo visualizzare, ognuna delle quali rappresenta una categoria diversa di dati. Ad esempio, il riquadro Approfondimenti mostra tre tracce per impostazione predefinita:

Man mano che aggiungiamo funzionalità al riquadro, prevediamo che verranno aggiunti altri brani.

Il nostro pensiero iniziale era che ciascuna traccia eseguisse il rendering del proprio <canvas>, in modo che la visualizzazione principale diventasse costituita da più elementi canvas impilati verticalmente. In questo modo, il rendering a livello di traccia sarebbe più semplice, perché ogni traccia potrebbe essere sottoposta a rendering in isolamento e non ci sarebbe il rischio che una traccia venga sottoposta a rendering al di fuori dei suoi limiti. Purtroppo, questo approccio presenta due problemi principali:

Il rendering (o il rendering ripetuto) degli elementi canvas è costoso; avere più canvas è più costoso di un solo canvas, anche se è più grande. Il rendering di eventuali overlay che si estendono su più tracce (ad esempio, linee verticali per contrassegnare eventi come l'ora FCP) diventa complesso: dobbiamo eseguire il rendering su più canvas e assicurarci che vengano tutti visualizzati insieme e si allineino correttamente.

L'utilizzo di un unico canvas per l'intera UI ci ha costretto a capire come assicurarci che ogni traccia venga visualizzata alle coordinate giuste e non si sovrapponga a un'altra traccia. Ad esempio, se una traccia specifica è alta 100 px, non possiamo consentire il rendering di un elemento alto 120 px e farlo sovrapporre alla traccia sottostante. Per risolvere il problema, possiamo utilizzare clip. Prima di eseguire il rendering di ogni traccia, disegniamo un rettangolo che rappresenta la finestra della traccia visibile. In questo modo, tutti i percorsi disegnati al di fuori di questi limiti verranno ritagliati dalla tela.

canvasContext.beginPath();
canvasContext.rect(
    trackVisibleWindow.x, trackVisibleWindow.y, trackVisibleWindow.width, trackVisibleWindow.height);
canvasContext.clip();

Inoltre, non volevamo che ogni traccia dovesse conoscere la propria posizione verticale: ogni traccia deve essere visualizzata come se fosse visualizzata in (0, 0) e abbiamo un componente di livello superiore (che chiamiamo TrackManager) per gestire la posizione complessiva della traccia. Questa operazione può essere eseguita con translate, che trasla il canvas di una determinata posizione (x, y). Ad esempio:

canvasContext.translate(0, 10); // Translate by 10px in the y direction
canvasContext.rect(0, 0, 10, 10); // draw a rectangle at (0, 0) that’s 10px high and wide

Nonostante l'impostazione del codice rect come posizione 0, 0, la traduzione complessiva applicata farà sì che il rettangolo venga visualizzato in 0, 10. In questo modo possiamo lavorare su base di traccia come se stessimo eseguendo il rendering a (0, 0) e fare in modo che Track Manager esegua la traduzione durante il rendering di ogni traccia per garantire che ogni traccia venga visualizzata correttamente sotto la precedente.

Canvas fuori schermo per tracce e momenti salienti

Il rendering del canvas è relativamente costoso e vogliamo assicurarci che il pannello Approfondimenti rimanga fluido e reattivo mentre lo utilizzi. A volte non puoi evitare di dover eseguire nuovamente il rendering dell'intero canvas: ad esempio, se modifichi il livello di zoom, dobbiamo ricominciare e renderizzare tutto. Il rendering della tela è particolarmente costoso perché non puoi eseguire il rendering solo di una piccola parte, ma devi cancellare l'intera tela e ridisegnarla. A differenza del rendering del DOM, in cui gli strumenti possono calcolare il lavoro minimo richiesto e non rimuovere tutto e ricominciare da capo.

Un'area in cui abbiamo riscontrato problemi visivi è l'evidenziazione. Quando passi il mouse sopra le metriche nel riquadro, le evidenziamo sulla sequenza temporale e, allo stesso modo, se passi il mouse sopra un insight per un determinato evento, disegniamo un bordo blu intorno all'evento.

Questa funzionalità è stata implementata per la prima volta rilevando lo spostamento del mouse su un elemento che attiva un'evidenziazione, quindi disegnando l'evidenziazione direttamente sul canvas principale. Il problema si presenta quando dobbiamo rimuovere l'evidenziazione: l'unica opzione è ridisegnare tutto. È impossibile ridisegnare solo l'area in cui si trovava l'evidenziazione (non senza enormi modifiche architetturali), ma ridisegnare l'intera tela solo perché vogliamo rimuovere un bordo blu intorno a un elemento ci è sembrato eccessivo. Inoltre, si verificava un ritardo visivo se spostavi rapidamente il mouse su diversi elementi per attivare più evidenziazioni in rapida successione.

Per risolvere questo problema, abbiamo suddiviso la nostra UI in due canvas fuori schermo: il canvas "principale", in cui vengono visualizzate le tracce, e il canvas "highlights", in cui vengono disegnati gli highlights. Quindi, eseguiamo il rendering copiando queste tele sul singolo canvas visibile sullo schermo all'utente. Possiamo utilizzare il metodo drawImage in un contesto canvas, che può prendere un altro canvas come origine.

In questo modo, la rimozione di un'evidenziazione non comporta il ridisegno del canvas principale: possiamo invece cancellare il canvas sullo schermo e poi copiare il canvas principale sul canvas visibile. La copia di un canvas è economica, il disegno è costoso, quindi spostando gli highlight su un canvas separato, evitiamo questo costo quando attiviamo e disattiviamo gli highlight.

Analisi delle tracce testata in modo completo

Uno dei vantaggi della creazione di una nuova funzionalità da zero è la possibilità di riflettere sulle scelte tecniche fatte in precedenza e apportare miglioramenti. Uno degli aspetti che volevamo migliorare era la suddivisione esplicita del codice in due parti quasi completamente distinte:

Analizza il file di traccia ed estrai i dati richiesti. Esegui il rendering di un insieme di tracce.

Mantenere l'analisi (parte 1) separata dal lavoro dell'interfaccia utente (parte 2) ci ha permesso di creare un sistema di analisi solido; ogni traccia viene eseguita tramite una serie di gestori responsabili di diversi problemi: un LayoutShiftHandler calcola tutte le informazioni necessarie per gli spostamenti del layout e un NetworkRequestsHandler si occupa esclusivamente di estrarre le richieste di rete. Anche la presenza di questo passaggio di analisi esplicita, in cui diversi gestori sono responsabili di diverse parti della traccia, è stata utile: l'analisi della traccia può diventare molto complicata ed è utile potersi concentrare su un problema alla volta.

Siamo anche riusciti a testare in modo completo l'analisi delle tracce registrando in DevTools, salvandole e caricandole come parte della nostra suite di test. Questo è un vantaggio perché possiamo eseguire test con tracce reali e non accumulare enormi quantità di dati di traccia falsi che potrebbero diventare obsoleti.

Test degli screenshot per l'interfaccia utente del canvas

Rimanendo in tema di test, di solito testiamo i nostri componenti frontend eseguendone il rendering nel browser e assicurandoci che si comportino come previsto. Possiamo inviare eventi di clic per attivare gli aggiornamenti e verificare che il DOM generato dai componenti sia corretto. Questo approccio funziona bene per noi, ma non è adatto al rendering su una tela: non è possibile ispezionare una tela e determinare cosa è stato disegnato. Pertanto, il nostro solito approccio di rendering e poi di query non è appropriato.

Per consentirci di avere una copertura dei test, abbiamo optato per i test degli screenshot. Ogni test attiva un canvas, esegue il rendering della traccia che vogliamo testare e poi acquisisce uno screenshot dell'elemento canvas. Questo screenshot viene quindi archiviato nel nostro codebase e le esecuzioni di test future confronteranno lo screenshot archiviato con quello generato. Se gli screenshot sono diversi, il test non andrà a buon fine. Forniamo anche un flag per eseguire il test e forzare un aggiornamento dello screenshot quando abbiamo modificato intenzionalmente il rendering e dobbiamo aggiornare il test.

I test degli screenshot non sono perfetti e sono un po' approssimativi: puoi solo verificare che l'intero componente venga visualizzato come previsto, anziché asserzioni più specifiche. Inizialmente, li abbiamo usati eccessivamente per assicurarci che ogni singolo componente (HTML o canvas) venisse visualizzato correttamente. Ciò ha rallentato drasticamente la nostra suite di test e ha portato a problemi in cui piccole modifiche quasi irrilevanti dell'interfaccia utente (come lievi modifiche del colore o l'aggiunta di un margine tra gli elementi) hanno causato l'esito negativo di più screenshot e hanno richiesto l'aggiornamento. Ora abbiamo ridotto l'utilizzo degli screenshot e li utilizziamo esclusivamente per i componenti basati su canvas. Questo equilibrio ha funzionato bene finora.

Conclusione

La creazione del nuovo riquadro Informazioni sulle prestazioni è stata un'esperienza molto piacevole e istruttiva per il team. Abbiamo imparato molto sui file di traccia, sull'utilizzo del canvas e molto altro ancora. Ci auguriamo che ti piaccia usare il nuovo pannello e non vediamo l'ora di ricevere il tuo feedback.

Per saperne di più sul pannello Informazioni sul rendimento, consulta Informazioni sul rendimento: ottieni informazioni strategiche sul rendimento del tuo sito web.

Scaricare i canali in anteprima

Prendi in considerazione l'utilizzo di Chrome Canary, Dev o Beta come browser di sviluppo predefinito. Questi canali di anteprima ti consentono di accedere alle funzionalità più recenti di DevTools, testare le API della piattaforma web all'avanguardia e trovare problemi sul tuo sito prima che lo facciano i tuoi utenti.

Contatta il team di Chrome DevTools

Utilizza le seguenti opzioni per discutere delle nuove funzionalità, degli aggiornamenti o di qualsiasi altro argomento relativo a DevTools.