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.
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.markeperformance.measureper marcare blocchi del tuo codice.
Le quattro categorie di lentezza
| Categoria | Sintomo utente | Strumento di prima linea |
|---|---|---|
| CPU (JavaScript) | UI bloccata, scroll a scatti | Performance panel, flamegraph |
| Rendering | pagine “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:
- Riduci rumore: chiudi tab inutili.
- Stop al primo problema (registrazioni lunghe = analisi complicata).
- 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/heightsulle immagini. - Riserva spazio per ad/embed.
min-heightsu 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
- Apri Lighthouse su un sito di tuo gusto. Annota LCP, INP, CLS, TTFB.
- Apri Performance panel: registra un caricamento + interazione.
- Identifica il long task più rumoroso. Quale funzione?
- Marca due blocchi del tuo codice con
performance.mark/measuree verifica che appaiano in Performance. - Installa
web-vitalsin 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.