INP come Ranking Signal: Architettura dello Yielding

Google ha promosso INP a segnale di ranking primario. Il problema non è la velocità di rete, ma lo scheduling del thread principale.

Frontend Architecture

Tempo di lettura: 4 min


Per anni abbiamo trattato la performance come un problema di rete: comprimi gli asset, riduci il bundle, ottimizza il caricamento.

Il 43% dei siti fallisce ancora la soglia INP, e la rete non c’entra quasi mai.

Google ha promosso l’Interaction to Next Paint a segnale di ranking primario, allo stesso livello di LCP e CLS, abbassando la soglia “good” da 200 a 150 millisecondi. La causa delle bocciature non è quasi mai la latenza: è il modo in cui il codice occupa il thread principale.

Questa è una guida architetturale per progettare lo scheduling, non solo il bundle.


Perché LCP e CLS Non Bastano più

LCP misura il caricamento; CLS misura la stabilità visiva. Nessuno dei due misura cosa succede quando un utente interagisce davvero con la pagina.

  • Un LCP eccellente può nascondere un thread bloccato: la pagina appare pronta, ma il primo click resta senza risposta per centinaia di millisecondi.
  • Gli script di terze parti sono spesso invisibili alle metriche di caricamento, ma occupano il main thread esattamente quando l’utente prova a interagire.
  • Il layout thrashing (letture e scritture del DOM alternate senza batching) aggiunge lavoro sincrono proprio nel momento più critico.

Strategic Insight: INP non misura la velocità del sito, misura la disciplina architetturale di chi scrive il codice che gira dopo il caricamento.


Lo Scheduling come Responsabilità Architetturale

Un Senior Architect non ottimizza singole funzioni: progetta il modo in cui il lavoro viene spezzato nel tempo.

// Prima: un task lungo blocca il thread per l'intera durata
function handleSearch(query) {
  const results = expensiveFilter(largeDataset, query);
  setResults(results);
}

// Dopo: useTransition cede priorità agli eventi urgenti
function handleSearch(query) {
  startTransition(() => {
    const results = expensiveFilter(largeDataset, query);
    setResults(results);
  });
}

useTransition e scheduler.yield() non rendono il lavoro più veloce: lo rendono interrompibile. Il browser può tornare a gestire un click o uno scroll prima di riprendere il task, invece di finire l’intero blocco sincrono.


Dove lo Yielding Non Basta

Spezzare i task lunghi è necessario, ma non risolve tutto da solo.

  1. Third-Party Script Fuori dal Tuo Controllo: Se una libreria esterna non cede il thread, nessuna disciplina interna la corregge: la soluzione architetturale è isolarla (Web Worker, Server Islands a caricamento differito) piuttosto che ottimizzarla.
  2. Event Handler Non Profilati: Un handler percepito come “leggero” può nascondere ricalcoli di layout costosi che emergono solo sotto carico reale.
  3. Falsa Interrompibilità: Spezzare un task in tanti micro-task senza cambiare la logica di business sposta il problema, non lo elimina.

Trade-off Reality: Lo yielding riduce la latenza percepita spostando il lavoro nel tempo, ma un’architettura che genera troppo lavoro resta lenta, solo in modo meno visibile.


Matrice: Cause INP vs Intervento Architetturale

CausaSintomoIntervento
Task JS LunghiClick senza risposta immediatascheduler.yield() / useTransition
Script di Terze PartiBlocchi imprevedibili non profilabiliIsolamento (Web Worker, caricamento differito)
Layout ThrashingJank durante l’interazioneBatching di letture/scritture DOM
Re-render SuperfluiLavoro ripetuto senza necessitàMemoizzazione automatica

Un sito veloce a caricare e lento a rispondere non è un sito performante: è un sito che ha ottimizzato la metrica sbagliata.


Conclusione: Progettare per l’Interruzione

Il Performance Budgeting tradizionale controlla cosa scarichi. L’architettura orientata all’INP controlla cosa fa il thread principale dopo che tutto è scaricato, mentre l’utente prova a usare la pagina.

Anche un’applicazione che ha eliminato ogni re-render superfluo può fallire INP se un singolo task lungo non cede mai il controllo. Sono due problemi diversi, entrambi architetturali, entrambi necessari.

La domanda da porsi non è “quanto è veloce il mio codice”, ma “per quanto tempo tiene occupato il thread prima di lasciar rispondere l’utente”.



Articoli correlati