modulo 09 / lezione 46

Performance, memoria e osservabilità

Profilare tempi, rendering, rete e Core Web Vitals

Misurare prima di ottimizzare distinguendo CPU, layout, rendering, asset, tempi di risposta. Leggere LCP, INP, CLS, TTFB.

60 min Debugging

In parole semplici

“L’app è lenta” non è una diagnosi: è un sintomo. La performance ha sotto-categorie diverse, ognuna misurabile, ognuna con strumenti specifici. Citazione di Knuth, ormai stagionata e sempre vera:

“Premature optimization is the root of all evil.”

Prima misuri, poi ottimizzi. Le Core Web Vitals sono le metriche utente-centriche standard del 2026.

Parole nuove

  • profilare: registrare il comportamento del programma nel tempo per identificare colli di bottiglia.
  • LCP (Largest Contentful Paint): tempo di rendering dell’elemento principale (idealmente < 2.5s).
  • INP (Interaction to Next Paint): latenza tra interazione e prossimo render (idealmente < 200ms).
  • CLS (Cumulative Layout Shift): spostamenti visuali inattesi (idealmente < 0.1).
  • TTFB (Time To First Byte): tempo prima del primo byte di risposta dal server.
  • User Timing API: API browser per marcare e misurare blocchi (performance.mark, performance.measure).

Cosa impari

  • Aprire il pannello Performance di DevTools.
  • Leggere e migliorare LCP, INP, CLS, TTFB.
  • Usare performance.mark e performance.measure per marcare blocchi del tuo codice.

Le quattro categorie di lentezza

CategoriaSintomo utenteStrumento di prima linea
CPU (JavaScript)UI bloccata, scroll a scattiPerformance panel, flamegraph
Renderingpagine “saltellanti”Layout shifts (CLS)
Rete”ferma su un caricamento”Network panel, TTFB
Caricamento asset”carica per sempre”LCP, asset size

Performance panel (Chrome)

DevTools → tab Performance → click rec → naviga/interagisci → stop.

Cosa vedi:

  • Timeline: ogni evento nel tempo (script, layout, paint, GPU).
  • Main thread: dove si concentra il lavoro JS.
  • Flame chart: gerarchia delle chiamate (bottom-up, call tree).
  • Network: caricamenti.
  • Interactions: input e relative INP.

Per profilare:

  1. Riduci rumore: chiudi tab inutili.
  2. Stop al primo problema (registrazioni lunghe = analisi complicata).
  3. Cerca il “lungo blocco rosso” (long task > 50ms): è il colpevole.

Core Web Vitals: definizioni operative

LCP

Tempo dal navigation start al rendering dell’elemento più grande del viewport (immagine eroe, titolo H1, blocco testo).

Target: < 2.5s “good”, 2.5-4s “needs improvement”, > 4s “poor”.

Cause tipiche:

  • Hero image pesante non ottimizzata.
  • Font che blocca il rendering.
  • Server lento (TTFB).
  • JS che ritarda il render.

Cure:

  • Preload immagine hero.
  • font-display: swap.
  • Riduci JS critical.
  • CDN.

INP

Latenza percepita tra ogni interazione (click, tap, tasto) e il prossimo paint visibile.

Target: < 200ms “good”.

Cause tipiche:

  • Handler JS lento (validazione, calcolo).
  • Re-render eccessivo del framework.
  • Layout reflow scatenato dall’interazione.

Cure:

  • Debounce/throttle (modulo 7).
  • useMemo/memoization.
  • Splitta long task (requestIdleCallback, scheduler.yield()).

CLS

Somma degli spostamenti di layout inattesi (immagini senza dimensione, banner che spunta dopo il caricamento).

Target: < 0.1.

Cure:

  • Specifica width/height sulle immagini.
  • Riserva spazio per ad/embed.
  • min-height su contenitori dinamici.

TTFB

Tempo dal click al primo byte. Server-side, ma misurabile lato client.

Target: < 800ms.

Cause:

  • DB lento.
  • Computo server pesante.
  • Geografia (CDN).

User Timing API

Marca blocchi del tuo codice:

performance.mark("calcolo-start");
// ... operazione ...
performance.mark("calcolo-end");
performance.measure("calcolo", "calcolo-start", "calcolo-end");

In DevTools Performance vedi calcolo come blocco nominato nella timeline. Confronta diverse misurazioni nel tempo.

API moderna performance.now():

const t0 = performance.now();
// ...
const dt = performance.now() - t0;
console.log("durata:", dt.toFixed(2), "ms");

Più preciso di Date.now().

Lighthouse

DevTools → tab Lighthouse → analizza la pagina. Restituisce:

  • Performance (con Core Web Vitals).
  • Accessibility.
  • Best practices.
  • SEO.

Limitazioni: la misura è in un “ambiente simulato”. Per misure reali, usa Real User Monitoring (RUM) (modulo 9.4).

Misurare in produzione

Le metriche di laboratorio (Lighthouse) sono utili. Le metriche di utenti reali lo sono di più. Strumenti:

  • web-vitals.js (libreria Google) cattura Core Web Vitals dal client e li invia al tuo endpoint.
  • Vercel Analytics, Cloudflare Web Analytics, PageSpeed Insights + CrUX.

Esempio:

import { onLCP, onINP, onCLS, onTTFB } from "web-vitals";

onLCP(metric => sendToAnalytics(metric));
onINP(metric => sendToAnalytics(metric));
onCLS(metric => sendToAnalytics(metric));
onTTFB(metric => sendToAnalytics(metric));

Esercizio guidato

  1. Apri Lighthouse su un sito di tuo gusto. Annota LCP, INP, CLS, TTFB.
  2. Apri Performance panel: registra un caricamento + interazione.
  3. Identifica il long task più rumoroso. Quale funzione?
  4. Marca due blocchi del tuo codice con performance.mark/measure e verifica che appaiano in Performance.
  5. Installa web-vitals in un tuo progetto e logga le metriche.

Errori frequenti del principiante

  • Ottimizzare senza misurare. Quasi sempre ottimizzi la parte sbagliata.
  • Solo Lighthouse, mai utenti reali. Lighthouse è simulato.
  • Confondere lentezza percepita con lentezza misurata. A volte un loader animato risolve il problema senza ottimizzare.
  • Misurare in dev (con HMR, DevTools aperti). Usa build di produzione.