Utilizzare il riquadro Prestazioni di Chrome DevTools per profilare le app Angular

Andrés Olivares
Andrés Olivares
Pawel Kozlowski
Pawel Kozlowski

I framework web come Angular, React, Vue e Svelte semplificano la scrittura e la manutenzione di applicazioni web complesse su larga scala.

Tuttavia, questi framework introducono un livello di astrazione sopra il modello di applicazione del browser. Infatti, il codice scritto dagli sviluppatori che utilizzano queste astrazioni di solito viene transpilato in codice illeggibile, compresso e raggruppato. Di conseguenza, sfruttare appieno la potenza dei DevTools per eseguire il debug e la profilazione di queste app può essere difficile per gli sviluppatori.

Ad esempio, quando profili un'applicazione Angular con il riquadro Rendimento in DevTools, ecco cosa vedi:

La visualizzazione della traccia del pannello Rendimento che mostra la sequenza temporale del caricamento di una pagina ottenuta da un'app Angular. Si concentra sulla corsia principale espansa, che mostra un grafico a fiamme delle chiamate JavaScript con nomi compressi.
Visualizzazione della traccia del riquadro Prestazioni.

Con le informazioni presentate in questo modo, può essere difficile capire quali colli di bottiglia delle prestazioni esistono nel tuo codebase. Dopo tutto, manca il contesto dei costrutti del framework e una buona parte delle informazioni mostrate è in termini di codice compresso. È anche difficile distinguere tra l'attività direttamente correlata al codice che hai scritto, ai dettagli interni del framework e ad altro codice di terze parti che potrebbe essere eseguito sulla stessa pagina.

Un motivo comune per gli autori di framework e astrazioni è implementare le proprie estensioni DevTools che presentano i dati di profilazione in termini di concetti del framework. Questi strumenti sono molto utili per il debug e la profilazione delle applicazioni create con un framework specifico. Tuttavia, il più delle volte avrai bisogno di correlare i dati del framework nel profiler del framework con le informazioni sul runtime del browser nel riquadro Prestazioni di DevTools. La presentazione separata di queste due origini dati in strumenti indipendenti rende difficile individuare e risolvere i colli di bottiglia, soprattutto man mano che l'applicazione diventa più complessa. Ecco un esempio di visualizzazione del profilo in Angular DevTools Profiler:

La scheda Profiler in Angular DevTools, che mostra un grafico a fiamma del runtime di un'app Angular. Gli elementi che compongono il grafico a fiamma hanno etichette leggibili che ricordano i nomi dei componenti Angular.
Profiler di Angular DevTools.

In uno scenario ideale, gli sviluppatori avrebbero una visualizzazione in cui le due origini dati vengono mostrate insieme nello stesso contesto mappato sulla stessa cronologia.

Per questo motivo, abbiamo collaborato con il team di Angular per integrare i dati di runtime di Angular direttamente nel riquadro Rendimento utilizzando l'API di estensibilità del riquadro Rendimento. In questo post esamineremo le funzionalità dell'API e come è stata utilizzata nel framework Angular per raggiungere questo obiettivo. L'implementazione può fungere da esempio per altri framework e astrazioni che mirano a migliorare l'esperienza degli sviluppatori strumentando i propri strumenti e aiutando gli sviluppatori che utilizzano Chrome DevTools.

Che cos'è l'API di estensibilità del riquadro Prestazioni?

L'API ti consente di aggiungere le tue voci di temporizzazione alla traccia del pannello Prestazioni, all'interno della stessa cronologia degli altri dati del browser. Esistono due meccanismi che ti consentono di farlo:

  • API User Timing
  • L'API console.timeStamp

API User Timing

Puoi utilizzare performance.mark e performance.measure per aggiungere le voci nel seguente modo:


// Mark used to represent the start of some activity you want to measure.
// In this case, the rendering of a component.
const renderStart = performance.now();

// ... later in your code

performance.measure("Component rendering", {
  start: renderStart,
  detail: {
    devtools: {
      dataType: "track-entry",
      track: "Components",
      color: "secondary",
      properties: [
        ["Render reason", "Props changed"],
        ["Priority", "low"]
      ],
    }
  }
});

In questo modo, alla traccia Componenti verrà aggiunta la misurazione alla cronologia:

La visualizzazione traccia del riquadro Prestazioni. Si concentra sulla traccia personalizzata espansa denominata "Componenti", che contiene una misurazione denominata "Rendering dei componenti".
Traccia personalizzata nel riquadro Prestazioni.

Questa API ti consente di aggiungere le voci al buffer della cronologia delle prestazioni, visualizzandole anche nell'interfaccia utente del riquadro Prestazioni di DevTools.

Scopri di più su questa API e sull'oggetto devtools nella documentazione.

L'API console.timeStamp

Questa API è un'alternativa leggera all'API User Timing. Utilizzando lo stesso esempio di prima, potresti avere:


// Mark used to represent the start of some activity you want to measure.
// In this case, the rendering of a component.
const renderStart = performance.now();

// ... later in your code

console.timeStamp(
"Component rendering",
/* start time */ renderStart,
/* end time (current time) */ undefined,
/* track name */ "Components",
 /* track group name */ undefined,
 /* color */ "secondary"
);

Questa API fornisce un metodo ad alte prestazioni per instrumentare le applicazioni: a differenza dell'alternativa API User Timing, non crea dati memorizzati nel buffer. Questa API aggiunge dati esclusivamente al riquadro **Prestazioni** in DevTools, il che significa che quando DevTools non registra una traccia, le chiamate all'API non vengono eseguite (non fanno nulla), il che le rende molto più veloci e adatte ai percorsi critici sensibili alle prestazioni. La scelta di utilizzare argomenti posizionali anziché un oggetto contenente tutti i parametri di personalizzazione serve anche a mantenere l'API il più leggera possibile.

Scopri di più sull'utilizzo di console.timeStamp per estendere il riquadro Prestazioni e sui parametri che puoi trasmettere nella documentazione.

In che modo Angular ha integrato l'API di estensibilità di DevTools

Vedremo come il team di Angular ha utilizzato l'API di estensibilità per l'integrazione con Chrome DevTools.

Evita l'overhead con console.timestamp

L'instrumentazione di Angular con l'API di estensibilità del riquadro Rendimento è disponibile a partire dalla versione 20. Il livello di granularità richiesto per i dati sul rendimento in DevTools richiede un'API rapida, pertanto la richiesta pull (60217) che ha aggiunto la strumentazione ha scelto di utilizzare l'API console.timeStamp. In questo modo, il rendimento del runtime dell'applicazione non viene influenzato dal potenziale overhead dell'API Profiling.

Dati strumentati

Per fornire un quadro chiaro del codice Angular in esecuzione e del motivo per cui viene eseguito, sono strumentate più parti delle pipeline di avvio e rendering, tra cui:

  • Bootstrapping di applicazioni e componenti.
  • Creazione e aggiornamenti dei componenti.
  • Esecuzione di listener di eventi e hook del ciclo di vita.
  • Molti altri (ad esempio, la creazione dinamica di componenti e il rendering differito dei blocchi).

Codifica con colori

La codifica a colori viene utilizzata per segnalare allo sviluppatore la categoria in cui rientra una determinata voce di misurazione. Ad esempio, i colori utilizzati per le voci che contrassegnano l'esecuzione del codice TypeScript creato dallo sviluppatore sono diversi da quelli utilizzati per il codice prodotto dal compilatore Angular.

Nello screenshot seguente puoi vedere come questo si traduce in punti di ingresso (come il rilevamento delle modifiche e l'elaborazione dei componenti) in blu, codice generato in viola e codice TypeScript (come listener di eventi e hook) visualizzato in verde.

La visualizzazione traccia del riquadro Prestazioni. Si concentra sulla traccia personalizzata espansa denominata "Angular", che contiene un flamegraph con misurazioni con colori diversi che rappresentano l'attività di runtime di un'app Angular in modo semplice per gli sviluppatori.
Codifica con colori nel riquadro Prestazioni.

Tieni presente che l'argomento colore passato all'API non è un valore di colore CSS, ma un token semantico mappato a un colore che corrisponde all'interfaccia utente di DevTools. I valori possibili sono primary, secondary e tertiary, con le rispettive varianti -dark e -light, nonché un colore error.

Tracce

Al momento della scrittura, tutti i dati di runtime di Angular vengono aggiunti alla stessa traccia (etichettata "🅰️ Angular"). Tuttavia, è possibile aggiungere più tracce alla traccia e persino raggrupparle. Ad esempio, date le seguenti chiamate all'API console.timeStamp:

console.timeStamp("Component 1", componentStart1, componentEnd1, "Components", "Client", "primary");
console.timeStamp("Component 2", componentStart2, componentEnd2, "Components", "Client", "primary");
console.timeStamp("Hook 1", hookStart, hookEnd, "Hooks", "Client", "primary");
console.timeStamp("Fetch data base", fetchStart, fetchEnd, "Server", "primary");

Vedrai i dati organizzati in tracce nel seguente modo:

La visualizzazione traccia del riquadro Prestazioni. Si concentra sulle varie tracce personalizzate espanse, ognuna con misurazioni diverse.
Più tracce personalizzate nel riquadro Rendimento.

L'utilizzo di tracce separate può essere utile, ad esempio, quando hai attività asincrone, più job in esecuzione in parallelo o semplicemente gruppi di attività sufficientemente distinti da meritare di essere separati in diverse aree dell'interfaccia utente.

Perché è importante per gli sviluppatori Angular

L'obiettivo di questa integrazione diretta è fornire un'esperienza di analisi del rendimento più intuitiva e completa. Visualizzando i dati sul rendimento interni di Angular direttamente nel riquadro **Rendimento**, gli sviluppatori otterranno:

  • Maggiore visibilità: rendendo visibili nella sequenza temporale più ampia del browser eventi di rendimento specifici di Angular, come il rendering dei componenti, i cicli di rilevamento delle modifiche e altro ancora.
  • Comprensione migliorata: grazie a informazioni ricche di contesto sui processi interni di Angular, che ti aiutano a individuare i colli di bottiglia delle prestazioni in modo più efficace.

Attivazione dell'integrazione

L'utilizzo dell'API di estensibilità è ufficialmente disponibile nelle build di sviluppo a partire dalla versione 20 di Angular. Per abilitarlo, devi eseguire l'utilità globale `ng.enableProfiling()` nella tua app o nella console DevTools. Per saperne di più sull'integrazione, consulta la [documentazione di Angular](https://angular.dev/best-practices/profiling-with-chrome-devtools).

Altre considerazioni

Alcune considerazioni importanti da tenere in considerazione.

Mappe di origine e codice minimizzato:

Le mappe di origine sono uno strumento ampiamente adottato che mira a colmare il divario tra il codice in bundle / minimizzato e la sua controparte creata, quindi…

Le mappe di origine non dovrebbero risolvere il problema del codice minimizzato nelle app in bundle?

Sebbene le mappe delle origini siano effettivamente utili, non eliminano completamente le sfide durante la profilazione di app web complesse sottoposte a minificazione. Le mappe di origine consentono a DevTools di mappare il codice minimizzato al codice sorgente originale, semplificando il debug. Tuttavia, fare affidamento esclusivamente sulle mappe delle origini per l'analisi del rendimento può comunque presentare alcune limitazioni. Ad esempio, scegliere il modo in cui gli elementi interni del framework e il codice creato vengono separati visivamente è complicato solo con le mappe di origine. L'API di estensibilità, invece, offre la flessibilità necessaria per ottenere questa distinzione e presentarla nel modo che lo sviluppatore ritiene più conveniente.

Estensioni di Chrome DevTools:

Le estensioni di Chrome che utilizzano l'API DevTools sono uno strumento ampiamente utilizzato per estendere DevTools.

Ora che questa API è disponibile, i profiler dedicati (ad esempio le estensioni di Chrome DevTools) sono inutili o sconsigliati?

No, questa API non è pensata per sostituire o scoraggiare lo sviluppo di profiler dedicati come le estensioni di Chrome DevTools. Questi possono comunque offrire funzionalità, visualizzazioni e flussi di lavoro specializzati su misura per esigenze specifiche. L'API di estensibilità del riquadro Rendimento mira a creare un'integrazione perfetta dei dati personalizzati con le visualizzazioni del browser nel riquadro Rendimento.

Il percorso futuro

La prospettiva dell'API di estensibilità.

Utilizzare più framework e astrazioni

Siamo entusiasti che altri framework e astrazioni adottino l'API per migliorare l'esperienza di profilazione dei loro sviluppatori. Ad esempio, React ha implementato un'adozione sperimentale dell'API per il proprio framework. Questa strumentazione mostra il rendering dei componenti client e server, nonché i dati delle API di pianificazione di React. Scopri di più su questa funzionalità e su come attivarla nella pagina di React.

Build di produzione

Uno degli obiettivi di questa API è collaborare con i framework e i fornitori di astrazioni in generale per adottare e abilitare la strumentazione nelle build di produzione. Ciò potrebbe avere un grande impatto sulle prestazioni delle app sviluppate con queste astrazioni, in quanto gli sviluppatori potrebbero profilare l'applicazione così come la vivono i loro utenti. Riteniamo che l'API console.timeStamp consenta di raggiungere questo obiettivo, data la sua velocità e il basso overhead. Tuttavia, al momento i framework stanno ancora sperimentando l'API e cercando di capire quali tipi di strumentazione sono più scalabili e utili per gli sviluppatori.