Come e perché abbiamo creato gli approfondimenti sulle prestazioni

In Chrome 102 noterai un nuovo riquadro sperimentale, Performance Insights, in DevTools. In questo post parleremo non solo dei motivi per cui abbiamo lavorato a un nuovo comitato, ma anche delle sfide tecniche che abbiamo affrontato e delle decisioni che abbiamo preso lungo il percorso.

ALT_TEXT_HERE

Perché creare un altro pannello?

Se non l'hai ancora fatto, abbiamo pubblicato un video sui motivi per cui è stato creato il riquadro Informazioni sul rendimento e su come utilizzarlo per ottenere informazioni strategiche sul rendimento del tuo sito web.

L'attuale riquadro sul rendimento è un'ottima risorsa se vuoi visualizzare tutti i dati del tuo sito web in un unico posto, ma abbiamo pensato che potesse essere un po' complesso. Se non sei un esperto di performance, è difficile sapere esattamente cosa cercare e quali parti della registrazione sono pertinenti.

Accedi al riquadro Approfondimenti, dove puoi comunque visualizzare una cronologia della traccia ed esaminare i dati, ma anche ottenere un pratico elenco di ciò che DevTools considera come le principali "informazioni" che vale la pena approfondire. Gli approfondimenti identificheranno problemi come richieste di blocco della visualizzazione, variazioni del layout e attività lunghe, per citarne alcuni. Tutti possono influire negativamente sulle prestazioni di caricamento delle pagine del tuo sito web e, in particolare, sui punteggi Segnali web essenziali (CWV) del tuo sito. Oltre alla segnalazione dei problemi, le informazioni sul rendimento ti forniscono suggerimenti utili per migliorare i punteggi del tuo CWV e fornisce link ad altre risorse e documentazione.

Link per il feedback nel riquadro

Questo riquadro è sperimentale e vorremmo ricevere il tuo feedback. Contattaci se riscontri bug o se hai richieste di funzionalità che ritieni ti aiuteranno a migliorare le prestazioni del tuo sito.

Come abbiamo creato le informazioni sulle prestazioni

Come per il resto degli strumenti DevTools, abbiamo creato Statistiche sulle prestazioni in TypeScript e abbiamo utilizzato componenti web supportati da lit-html per creare l'interfaccia utente. Le informazioni sul rendimento differiscono invece dal fatto che l'interfaccia utente principale è un elemento HTML canvas e la sequenza temporale è tracciata su questo canvas. Gran parte della complessità deriva dalla gestione di questo canvas: non solo tracciando i dettagli giusti nel posto giusto, ma anche dagli eventi del mouse (ad esempio, dove l'utente ha fatto clic sul canvas? Hanno fatto clic su un evento disegnato?) e si assicurano di eseguire il rendering efficace della tela.

Più tracce in un'unica canvas

Per un determinato sito web, vogliamo eseguire più "tracce" che rappresentano una categoria di dati diversa. Ad esempio, per impostazione predefinita il riquadro Approfondimenti mostrerà tre tracce:

E man mano che le funzionalità verranno aggiunte al panel, prevediamo di aggiungere altre tracce.

Inizialmente abbiamo pensato che ciascuna di queste tracce venisse visualizzata in modo indipendente su <canvas>, in modo che la visualizzazione principale diventasse più elementi canvas impilati verticalmente. Ciò semplificherebbe il rendering a livello di traccia, poiché ogni traccia potrebbe essere visualizzata in modo isolato e non ci sarebbe alcun pericolo che una traccia venga visualizzata al di fuori dei suoi limiti, ma sfortunatamente questo approccio presenta due problemi principali:

Gli elementi canvas sono costosi da (ri)renderizzare; la creazione di più tele è più costosa di una tela, anche se la tela è più grande. Il rendering di qualsiasi overlay che attraversa più tracce (ad esempio, linee verticali per contrassegnare eventi come l'ora FCP) diventa complesso: dobbiamo eseguire il rendering su più canvas e assicurarsi che tutti vengano visualizzati insieme e allinearli correttamente.

L'utilizzo di un solo canvas per l'intera UI ci ha richiesto di capire come assicurarci che ogni traccia venga visualizzata nelle giuste coordinate e non rientri in un'altra traccia. Ad esempio, se una determinata traccia è alta 100 px, non possiamo consentire il rendering di qualcosa di alto 120 px e farla apparire nella traccia sottostante. Per risolvere il problema, possiamo utilizzare clip. Prima di eseguire il rendering di ogni traccia, disegniamo un rettangolo che rappresenta la finestra visibile della traccia. In questo modo, i percorsi tracciati al di fuori di questi limiti verranno troncati dalla tela.

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

Inoltre, non volevamo che ogni traccia conoscesse la sua posizione verticalmente: ogni traccia dovrebbe mostrarsi come se fosse visualizzata a (0, 0) e abbiamo un componente di livello superiore (chiamato TrackManager) per gestire la posizione complessiva della traccia. Puoi farlo con translate, che traduce il canvas in 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 0, 0 come posizione, la traduzione complessiva applicata comporterà il rendering del rettangolo a 0, 10. In questo modo possiamo lavorare a livello di traccia come se stessimo eseguendo il rendering a (0, 0) e fare in modo che il nostro gestore della traccia traduca il rendering di ogni traccia, per garantire che ogni traccia venga visualizzata correttamente al di sotto della precedente.

Tele fuori schermo per tracce e momenti salienti

Il rendering del canvas è relativamente costoso e vogliamo assicurarci che il riquadro Approfondimenti rimanga fluido e reattivo mentre ci utilizzi. A volte non è possibile evitare di dover eseguire di nuovo il rendering dell'intero canvas: ad esempio, se modifichi il livello di zoom, dobbiamo ricominciare e eseguire il rendering di tutto. Il rendering di una tela è particolarmente costoso perché non è possibile solo rieseguire il rendering di una piccola parte; è necessario cancellare l'intera tela e ridisegnarla. Questo è diverso dal rendering del DOM, in cui gli strumenti possono calcolare il lavoro minimo richiesto senza rimuovere tutto e ricominciare.

Un'area in cui abbiamo riscontrato problemi visivi era l'evidenziazione. Quando passi il mouse sopra le metriche del riquadro, le evidenziamo nella sequenza temporale e, analogamente, se passi il mouse sopra un approfondimento per un determinato evento, disegniamo un bordo blu intorno all'evento.

Questa funzionalità è stata prima implementata rilevando il movimento del mouse sopra un elemento che attiva un'evidenziazione, per poi disegnandolo direttamente sul canvas principale. Il problema si presenta quando dobbiamo rimuovere l'evidenziazione: l'unica opzione è ritracciare tutto. È impossibile ridisegnare semplicemente l'area in cui si trovava l'evidenziazione (non senza enormi modifiche architettoniche), ma ridisegnare l'intera tela solo perché vogliamo rimuovere il bordo blu intorno a un elemento sembrava esagerato. Inoltre, non funzionava visivamente se spostavi rapidamente il mouse su diversi elementi per attivare più evidenziazioni in rapida successione.

Per risolvere il problema, abbiamo suddiviso l'interfaccia utente in due canvas fuori schermo: il canvas "principale", in cui vengono visualizzate le tracce e il canvas "evidenziazioni", in cui vengono tracciate le evidenziazioni. Il rendering viene quindi copiato copiando i canvas su un unico canvas visibile all'utente sullo schermo. Possiamo utilizzare il metodo drawImage in un contesto canvas, che può utilizzare un'altra tela come origine.

In questo modo, la rimozione di un'evidenziazione non comporta un nuovo disegno del canvas principale. In alternativa, possiamo cancellare il canvas sullo schermo e quindi copiare il canvas principale su quello visibile. Copiare una tela è economico, perché costoso è il disegno; quindi, spostando le evidenziazioni su un'altra tela, evitiamo questo costo quando attiviamo e disattiviamo le evidenziazioni.

Analisi delle tracce testata in modo completo

Uno dei vantaggi di creare una nuova funzionalità da zero è che ti permette di riflettere sulle scelte tecniche fatte in precedenza e apportare miglioramenti. Uno degli aspetti che volevamo migliorare era dividere esplicitamente il codice in due parti quasi completamente distinte:

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

Mantenere l'analisi (parte 1) separata dal lavoro dell'interfaccia utente (parte 2) ci ha consentito di creare un solido sistema di analisi. Ogni traccia viene eseguita attraverso una serie di gestori responsabili di diversi problemi: un LayoutShiftHandler calcola tutte le informazioni necessarie per le variazioni di layout e un NetworkRequestsHandler affronta esclusivamente il pull delle richieste di rete. Anche questa fase di analisi esplicita, in cui abbiamo diversi gestori responsabili di diverse parti della traccia, è stata utile: l'analisi delle tracce può diventare molto complicata e ti consente di concentrarti su un problema alla volta.

Abbiamo anche potuto testare in modo completo l'analisi delle tracce registrando le registrazioni in DevTools, salvandole e caricandole come parte della nostra suite di test. Questo è ottimo perché possiamo eseguire test con tracce reali e non generare enormi quantità di dati di traccia falsi che potrebbero diventare obsoleti.

Test degli screenshot per l'interfaccia utente canvas

Per quanto riguarda i test, solitamente testiamo i nostri componenti frontend eseguendone il rendering nel browser e assicurandoci che si comportino come previsto. Possiamo inviare eventi di clic per attivare aggiornamenti e dichiarare che il DOM generato dai componenti è corretto. Questo approccio funziona bene per noi, ma se si considera il rendering su una tela non funziona; non c'è modo di ispezionare una tela e determinare cosa sia disegnato lì. Di conseguenza, il nostro approccio standard, che prevede il rendering e l'esecuzione di query, non è appropriato.

Per consentirci di effettuare alcuni test di copertura, ci siamo rivolti al test degli screenshot. Per ogni test viene attivato un canvas, viene visualizzata la traccia che vogliamo testare e poi viene acquisito uno screenshot dell'elemento canvas. Lo screenshot viene quindi archiviato nel nostro codebase e le successive esecuzioni di test confronteranno lo screenshot archiviato con lo screenshot generato. Se gli screenshot sono diversi, il test avrà esito negativo. Forniamo anche un flag per eseguire il test e forzare l'aggiornamento di uno screenshot quando abbiamo volutamente modificato il rendering e abbiamo bisogno che il test venga aggiornato.

I test degli screenshot non sono perfetti e sono un po' smussati; puoi verificare solo se l'intero componente esegue il rendering come previsto, piuttosto che con asserzioni più specifiche. All'inizio eravamo colpevoli di un uso eccessivo per garantire che ogni singolo componente (HTML o canvas) venisse visualizzato correttamente. Questo ha rallentato drasticamente la nostra suite di test e ha causato problemi per cui piccole modifiche dell'interfaccia utente quasi irrilevanti (come piccole modifiche di colore o l'aggiunta di qualche margine tra gli elementi) hanno causato l'esito negativo di più screenshot e richiedevano l'aggiornamento. Ora abbiamo ridotto l'utilizzo degli screenshot e li abbiamo utilizzati esclusivamente per i componenti basati su canvas e questo equilibrio ha funzionato bene fino a oggi.

Conclusione

La creazione del nuovo riquadro Informazioni sul rendimento è stata un'esperienza educativa e molto piacevole per il team. Abbiamo imparato molte cose sui file di traccia, l'uso di canvas e molto altro. Ci auguriamo che l'utilizzo del nuovo riquadro ti piaccia e non vediamo l'ora di ricevere il tuo feedback.

Per saperne di più sul riquadro Informazioni sul rendimento, consulta l'articolo Informazioni sul rendimento: ottieni informazioni strategiche sul rendimento del tuo sito web.

Scarica i canali in anteprima

Prendi in considerazione l'utilizzo di Chrome Canary, Dev o beta come browser di sviluppo predefinito. Questi canali in anteprima ti consentono di accedere alle funzionalità di DevTools più recenti, di testare le API per piattaforme web all'avanguardia e di individuare eventuali problemi sul tuo sito prima che lo facciano gli utenti.

Contattare il team di Chrome DevTools

Utilizza le opzioni seguenti per discutere delle nuove funzionalità e delle modifiche nel post o di qualsiasi altra cosa relativa a DevTools.

  • Inviaci un suggerimento o un feedback tramite crbug.com.
  • Segnala un problema DevTools utilizzando Altre opzioni   Altre   > Guida > Segnala i problemi di DevTools in DevTools.
  • Tweet all'indirizzo @ChromeDevTools.
  • Lascia commenti sui video di YouTube o sui suggerimenti di DevTools in DevTools Video di YouTube.