Performance

PerformanceObserver in pratica: cosa osservare e cosa no

PerformanceObserver legge le voci di performance senza polling. Chrome 155 espone 15 tipi di entry, 7 con buffer: quali servono e quali no.

In sintesi

  • PerformanceObserver riceve le voci quando il browser le produce, senza timer.
  • Chrome 155 espone 15 tipi di entry e 7 restituiscono voci con buffered: true.
  • Senza buffered perdi LCP e i long task emessi prima che lo script partisse.
  • Il supporto dei tipi cambia per browser: va letto, non supposto.

PerformanceObserver riceve le voci di performance man mano che il browser le produce, senza timer: con buffered recuperi anche quelle emesse prima che lo script partisse.

Cosa conviene osservare

Tipo di entryCosa contieneBufferedUso
largest-contentful-paintTempo e elemento del paint più grandesìLCP di campo
eventDurata e processingStart di un eventonodiagnosi INP
longtaskBlocchi oltre 50 mssìattribuzione dei blocchi
layout-shiftSpostamenti e nodi che li causanonodiagnosi CLS
resourceTempi e byte per richiestasìpeso e cache
navigationTempi del documentosìTTFB e FCP

Sei tipi coprono LCP, INP e CLS. Gli altri servono alla diagnosi: element e mark misurano ciò che il tuo codice segna, visibility-state dice quando la scheda è nascosta e permette di scartare le voci misurate in background.

Il pattern che regge

new PerformanceObserver((list) => {
  const body = JSON.stringify(
    list.getEntries().map((e) => ({
      name: e.name,
      start: Math.round(e.startTime),
      dur: Math.round(e.duration),
    })),
  );
  navigator.sendBeacon("/api/rum", new Blob([body], { type: "application/json" }));
}).observe({ type: "longtask", buffered: true });

Il codice richiede un browser con sendBeacon e un endpoint che accetti POST; senza endpoint sostituisci la chiamata con console.log. Un observer per tipo, non un observer per evento: la callback riceve già una lista.

Tre errori comuni

  • Osservare senza buffered: le voci emesse prima dello script non arrivano.
  • Osservare layout-shift senza filtrare hadRecentInput: gli spostamenti causati da un clic non contano per il CLS.
  • Dimenticare disconnect() in una SPA: ogni navigazione aggiunge un observer e le voci si duplicano.

Il limite da dichiarare

Il set di tipi dipende dal browser. Chrome 155 ne espone 15, Firefox e Safari ne espongono meno e alcuni nomi non esistono; un observer che assume longtask su Safari non riceve nulla e non lancia errori. La copertura va controllata con PerformanceObserver.supportedEntryTypes, non supposta.

Dove continuare

Il catalogo EneUI indicizza 111.985 componenti, 12.808 icone e il record image auto slider: uno slider che ruota da solo produce voci anche quando nessuno lo guarda. Per il quadro delle metriche leggi cosa sono i Core Web Vitals, per la reattività INP in pratica, per il confronto tra analytics ospitato e self-hosted Vercel Analytics vs self-hosted.

Domande frequenti

PerformanceObserver sostituisce Lighthouse?

No. Lighthouse misura una pagina in laboratorio, PerformanceObserver legge ciò che il browser produce durante una visita reale.

Cosa fa buffered: true?

Chiede al browser le voci già emesse prima che l'observer partisse. Senza, perdi l'LCP e i long task del caricamento.

Quali tipi servono per le Core Web Vitals?

largest-contentful-paint per LCP, event per INP e layout-shift per CLS. Gli altri tipi aiutano a capire la causa.

Perché il mio observer non riceve nulla su Safari?

Perché quel tipo non è supportato. Controlla supportedEntryTypes e scrivi un ramo di riserva prima di osservare.

Come si evitano le voci duplicate?

Con un flag o un Set nella callback e con disconnect() quando smonti il componente. Con reportAllChanges le voci arrivano più volte.