Tempo di elaborazione dell'INP: Cause, ottimizzazione ed esempi di codice
Scopri come individuare e risolvere i problemi di INP causati dal tempo di elaborazione

Problemi di Interaction to Next Paint (INP) causati dal tempo di elaborazione
Questa pagina fa parte della nostra serie sull'Interaction to Next Paint (INP). L'INP misura il tempo totale da un'interazione dell'utente al successivo aggiornamento visivo. Il tempo di elaborazione è la seconda delle tre fasi che compongono l'INP, preceduta dall'input delay e seguita dal presentation delay. Se non hai familiarità con l'INP, leggi prima la nostra guida su come individuare e risolvere i problemi di INP.
In breve: L'Interaction to Next Paint (INP) misura quanto tempo impiega un utente per vedere un cambiamento visivo su una pagina dopo aver interagito con essa. Questo INP può essere suddiviso in 3 componenti: "input delay", "tempo di elaborazione" e "presentation delay".
Il tempo di elaborazione contribuisce in modo significativo all'INP totale, rappresentando in media circa il 40% del ritardo. L'ottimizzazione dei gestori di eventi è il modo più diretto per ridurre il tempo di elaborazione e migliorare il tuo punteggio INP.
SUGGERIMENTO INP: il tempo di elaborazione può essere ottimizzato eseguendo immediatamente il codice importante che precede l'aggiornamento del layout e programmando l'esecuzione di tutto il resto del codice successivamente.
Table of Contents!
- Problemi di Interaction to Next Paint (INP) causati dal tempo di elaborazione
- Cos'è il tempo di elaborazione?
- Il tempo di elaborazione e l'INP
- Cosa causa un tempo di elaborazione elevato?
- Minimizzare il tempo di elaborazione
- Suddividere i gestori di eventi con setTimeout(0)
- Usare requestAnimationFrame per gli aggiornamenti visivi
- Come dare priorità al codice critico
- Pianificazione a grana fine con scheduler.postTask()
- Implicazioni pratiche
- Esplora le altre fasi dell'INP
Cos'è il tempo di elaborazione?

L'Interaction to Next Paint (INP) può essere suddiviso in 3 sottoparti: "Input Delay", "Tempo di elaborazione" e "Presentation Delay".
Il tempo di elaborazione si riferisce al tempo impiegato dal browser per eseguire tutte le callback degli eventi associati dopo che un utente interagisce con una pagina web (ad esempio, cliccando su un pulsante o premendo un tasto). Sebbene ci sia sempre un certo tempo di elaborazione, i problemi di INP si verificano quando le callback degli eventi occupano troppo tempo di elaborazione.
In parole povere: il tempo di elaborazione è la durata del "lavoro" che avviene in risposta alla tua interazione. Quando clicchi su un pulsante di ricerca, il tempo di elaborazione include tutto, dalla convalida della tua query, alla preparazione della richiesta API, all'aggiornamento dello stato locale, all'attivazione degli eventi di analisi e a qualsiasi altro codice associato a quell'evento di clic. Ogni riga di JavaScript in quei gestori di eventi contribuisce al tempo di elaborazione.
Il tempo di elaborazione e l'INP
Il tempo di elaborazione potrebbe essere la prima cosa che viene in mente quando si pensa a ottimizzare l'Interaction to Next Paint. È il "lavoro che deve essere svolto" prima che il layout possa essere aggiornato dal browser.
Molti sviluppatori pensano di migliorare l'INP in termini di ottimizzazione delle funzioni di callback (ottimizzando il tempo di elaborazione), e hanno ragione. Tuttavia, in termini di importanza, il tempo di elaborazione non è nemmeno la singola parte più importante da migliorare. Esso costituisce ancora, in media, circa il 40% del tempo INP totale.

In CoreDash raccogliamo milioni di data point sui Core Web Vitals ogni ora. Sulla base di questi dati, il tempo di elaborazione rappresenta il 40% dell'Interaction to Next Paint. Il 40% è molto, ma ottimizzare solo il tempo di elaborazione non risolverà i problemi di INP. Dovresti anche esaminare l'input delay (18%) e il presentation delay (42%).
Esempio di tempo di elaborazione: Quando un utente fa clic su un pulsante per inviare un modulo, il codice che convalida i dati del modulo, li invia al server e gestisce la risposta contribuisce per intero al tempo di elaborazione. Più lunghe sono queste operazioni, maggiore è il tempo di elaborazione e potenzialmente peggiore è il punteggio INP.
Cosa causa un tempo di elaborazione elevato?
Un tempo di elaborazione elevato ha quattro cause comuni: codice non necessario, codice non ottimizzato, callback raggruppate (clustered) e layout thrashing.

- Codice non necessario. Codice vecchio e inutilizzato o codice senza un'immediata rilevanza per l'interazione dell'utente può prolungare il tempo di esecuzione della callback. Questo include chiamate di analisi, registrazione (logging) e sincronizzazione dello stato che non necessitano di essere completati prima del successivo aggiornamento visivo (next paint).
- Codice non ottimizzato. Un codice inefficiente (solitamente cicli o ricerche DOM non efficienti) può far sì che le callback degli eventi vengano eseguite più lentamente del necessario. Un esempio comune è interrogare il DOM all'interno di un ciclo con
document.querySelectorAll()invece di memorizzare nella cache il risultato prima del ciclo. - Callback raggruppate. Molteplici callback di eventi programmate ravvicinate creano una coda. Se una callback attivata dall'interazione dell'utente rimane bloccata in questa coda, la risposta appare ritardata. Ad esempio, un gestore
pointerdown, un gestoremousedowne un gestoreclickpossono tutti attivarsi sequenzialmente per un singolo clic. - Layout thrashing. Frequenti manipolazioni del DOM che innescano ricalcoli del layout possono sovraccaricare il browser e portare a regressioni delle prestazioni. Questo si verifica quando il tuo codice alterna la lettura e la scrittura delle proprietà di layout all'interno di un ciclo, forzando il browser a ricalcolare il layout più volte.
Minimizzare il tempo di elaborazione

La strategia è duplice: ottimizzare il codice esistente (rimuovere il codice non necessario e ottimizzare il codice corrente) e distinguere tra il codice che deve essere eseguito prima e dopo l'aggiornamento del layout. Il codice che è critico per l'aggiornamento del layout deve essere eseguito per primo, e tutto il resto del codice può essere eseguito dopo l'aggiornamento del layout.
- Rimuovere il codice inutilizzato. Sebbene rimuovere il codice inutilizzato possa sembrare scontato, sulla maggior parte dei siti c'è almeno un po' di vecchio codice inutilizzato che viene semplicemente eseguito senza aggiungere realmente nulla alla pagina né alla UX. La prima cosa da fare è assicurarsi che non sia in esecuzione codice non necessario. Questo può essere fatto tramite tree shaking, code splitting, ispezionando la copertura del codice (code coverage) in Chrome e utilizzando un buon IDE che suggerirà il codice inutilizzato. (Suggerimento pro: dai anche un'occhiata critica alle risorse caricate dal tuo Tag Manager). Per ulteriori strategie, consulta la nostra guida su 14 metodi per posticipare (defer) JavaScript.
- Ridurre al minimo il tempo di esecuzione della callback. Utilizza un profiler JavaScript per identificare i colli di bottiglia nel tuo codice e concentrati su quelle aree per l'ottimizzazione. Prendi in considerazione tecniche come la memoizzazione, il pre-calcolo e il caching per evitare calcoli ridondanti. (Suggerimento: puoi usare il pannello delle prestazioni di Chrome per trovare gli script con un lungo tempo di esecuzione).
- Dare priorità al codice critico e pianificare l'altro codice. Quando il codice della callback è stato ottimizzato, dividi il codice in codice che deve essere eseguito immediatamente e codice che può essere posticipato. Dai un'occhiata a questo esempio di vita reale:

In questo esempio, le callback degli eventi di Google Tag Manager e Facebook vengono eseguite prima del codice (React) che precede l'aggiornamento del layout. La soluzione è programmare le callback di GTM e Facebook in modo che vengano eseguite quando il browser è inattivo (idle). - Evitare layout thrashing o reflow. Il layout thrashing si verifica quando gli aggiornamenti di stile e le letture di stile vengono mescolati in un ciclo, costringendo il browser a ricalcolare il layout numerose volte. Per evitare il layout thrashing, esegui tutte le modifiche di stile (i "set") prima di richiedere i valori di stile (i "get"). Questo approccio riduce al minimo la frequenza degli aggiornamenti del layout, portando a una pagina più veloce. Ad esempio, in un ciclo che imposta la larghezza di ogni paragrafo in modo che corrisponda alla larghezza di un elemento, leggi la larghezza dell'elemento una volta prima del ciclo e usa quel valore per aggiornare le larghezze dei paragrafi all'interno del ciclo.
Suddividere i gestori di eventi con setTimeout(0)
Quando non puoi rimuovere o posticipare il codice da un gestore di eventi, la migliore opzione successiva è suddividere il gestore in blocchi più piccoli. Il pattern setTimeout(callback, 0) ti consente di dividere il lavoro su più attività (task), dando al browser l'opportunità di gestire l'aggiornamento del layout tra di esse. Ecco un esempio pratico:
// Prima: un lungo gestore di eventi blocca il successivo aggiornamento visivo (next paint)
button.addEventListener('click', () => {
updateUI(); // Critico: deve essere eseguito prima dell'aggiornamento (paint)
validateForm(); // Importante ma può attendere
sendAnalytics(); // Non critico
syncLocalStorage(); // Non critico
});
// Dopo: suddividi in lavoro critico e posticipato
button.addEventListener('click', () => {
updateUI(); // Critico: viene eseguito immediatamente prima dell'aggiornamento (paint)
setTimeout(() => {
validateForm();
}, 0);
setTimeout(() => {
sendAnalytics();
syncLocalStorage();
}, 0);
});
Lo svantaggio di setTimeout(0) è che posiziona la continuazione alla fine della coda delle attività. Se altre attività sono già in coda, il codice posticipato potrebbe non essere eseguito immediatamente. Per un comportamento più prevedibile, usa invece scheduler.yield() (vedi la sezione seguente). Per i pattern che mirano specificamente alla gestione dello scorrimento in JavaScript, consulta la nostra guida dedicata.
Usare requestAnimationFrame per gli aggiornamenti visivi
Quando il tuo gestore di eventi deve innescare un aggiornamento visivo, requestAnimationFrame() assicura che il tuo codice venga eseguito nel momento ottimale: subito prima che il browser esegua il suo successivo repaint. Questo è particolarmente utile quando hai bisogno di raggruppare le letture e le scritture del DOM in batch per evitare il layout thrashing.
// Usa requestAnimationFrame per raggruppare gli aggiornamenti visivi
button.addEventListener('click', () => {
// Leggi prima le proprietà di layout (fuori da rAF)
const containerWidth = container.offsetWidth;
requestAnimationFrame(() => {
// Scrivi le proprietà di layout dentro rAF
items.forEach(item => {
item.style.width = containerWidth + 'px';
});
});
// Programma il lavoro non visivo per il tempo di inattività (idle time)
requestIdleCallback(() => {
trackButtonClick();
updateSessionState();
});
});
Questo pattern separa le letture del DOM dalle scritture del DOM, prevenendo un layout sincrono forzato. L'aggiornamento visivo viene eseguito nel momento ideale nella pipeline di rendering del browser, mentre il lavoro non visivo viene eseguito durante il tempo di inattività (idle time).
Come dare priorità al codice critico
"Dare priorità al codice critico e pianificare l'altro codice" sembra astratto, quindi ecco come appare in pratica. Possiamo dare priorità al codice critico usando requestIdleCallback() e cedendo (yielding) il controllo al thread principale.
Usiamo requestIdleCallback per le attività meno importanti che non devono essere eseguite immediatamente. Ecco un esempio "prima" e "dopo" la programmazione di un evento GTM:
/* prima: esegui immediatamente il codice */
gtag('event', '<event_name>', {
'event_category': '<event_category>',
});
/* dopo: esegui lo stesso codice durante l'inattività del browser */
requestIdleCallback(() => {
gtag('event', '<event_name>', {
'event_category': '<event_category>',
});
}, { timeout: 1000 });
Lo svantaggio di requestIdleCallback è che il codice potrebbe non essere eseguito non appena lo desideri. In tal caso, puoi "cedere (yield) al thread principale" dopo che il codice più importante è stato eseguito, dando al browser un momento per eseguire l'aggiornamento del layout. Ecco un esempio di come suddividere le attività cedendo (yielding) al thread principale:
async function yieldToMain() {
if ('scheduler' in window && 'yield' in window.scheduler) {
return await window.scheduler.yield();
}
return new Promise((resolve) => {
setTimeout(resolve, 0);
});
}
async function handleClick() {
// Fai gli aggiornamenti di layout più importanti qui
await yieldToMain();
// Esegui altre attività che devono essere eseguite il prima possibile dopo l'aggiornamento del layout
}
Pianificazione a grana fine con scheduler.postTask()
La funzione scheduler.postTask() fornisce una pianificazione a grana fine delle attività impostando le priorità, il che aiuta il browser a dare priorità al lavoro in modo che le attività a bassa priorità cedano (yield) il passo al thread principale. Controlla la tabella di supporto dei browser prima di usare questa API in produzione.
La funzione postTask() accetta tre impostazioni di priorità: "background" per le attività a priorità più bassa, "user-visible" per le attività a priorità media e "user-blocking" per le attività critiche che richiedono alta priorità.
Assegnando la giusta priorità a ogni parte del lavoro all'interno del tuo gestore di eventi, puoi assicurarti che il browser gestisca le interazioni dell'utente in modo reattivo, pur completando tutte le attività necessarie:
// Programma il lavoro critico dell'interfaccia utente (UI) ad alta priorità
scheduler.postTask(() => {
updateCartBadge();
showConfirmation();
}, { priority: 'user-blocking' });
// Programma la sincronizzazione dei dati a priorità media
scheduler.postTask(() => {
syncCartWithServer();
}, { priority: 'user-visible' });
// Programma l'analisi (analytics) a bassa priorità
scheduler.postTask(() => {
gtag('event', 'add_to_cart', { item: productId });
fbq('track', 'AddToCart');
}, { priority: 'background' });
Implicazioni pratiche
Ecco come affrontare l'ottimizzazione del tempo di elaborazione su WordPress e React/Next.js.
WordPress
WordPress offre un controllo limitato quando si tratta di script di terze parti. Molti script vengono aggiunti tramite i plugin. La maggior parte delle volte questi script aggiungeranno listener di eventi alla pagina che non fanno altro che ritardare l'Interaction to Next Paint (INP). Se il tuo sito WordPress sta riscontrando problemi con l'INP causati da un lungo tempo di elaborazione, segui questi passaggi:
- Controlla le impostazioni del tema. Deseleziona eventuali opzioni non necessarie come "smooth scroll" (scorrimento fluido) o "animated menu" (menu animato). Impostazioni come queste tendono a causare problemi di INP.
- Verifica quali script sono responsabili del lungo tempo di elaborazione (suggerimento: usa il pannello delle prestazioni di Chrome). Se tali script sono legati a plugin, considera di trovare un altro plugin che faccia all'incirca la stessa cosa con meno JavaScript.
- Spesso ci sono script personalizzati in esecuzione sulla pagina. Controlla questi script e assicurati che cedano (yield) spesso il controllo al thread principale e racchiudano le callback meno importanti in una funzione
requestIdleCallback. - Scarica gli script inutilizzati in base alla singola pagina (suggerimento: usa
wp_deregister_script). Alcuni plugin tendono a iniettare script su ogni pagina anche quando la funzionalità non è necessaria. - Controlla il tuo Tag Manager e rimuovi i tag inutilizzati o non necessari.
- Usa temi leggeri e puliti. I temi multiuso (multipurpose) che "fanno tutto" tendono ad avere più script e gestori di eventi più pesanti.
- Evita i page builder poiché spesso fanno un pesante affidamento su JavaScript per presentare le pagine all'utente finale.
React / Next.js
Gli hook di React e le funzionalità di concorrenza rendono possibile ridurre considerevolmente il tempo di elaborazione dell'INP. Ecco le tecniche chiave:
Dare priorità all'interazione dell'utente con le funzionalità di concorrenza di React:
React 18 ha introdotto funzionalità di concorrenza che ottimizzano il rendering per una user experience più fluida, in particolare durante l'input.
useTransitionestartTransition: Contrassegna gli aggiornamenti non critici per il rendering successivo. Questo impedisce ai grandi aggiornamenti di bloccare l'interazione dell'utente. Ad esempio, racchiudi un aggiornamento dei risultati di ricerca instartTransitionin modo che la digitazione nella casella di ricerca rimanga reattiva.useDeferredValue: Dividi la tua UI in sezioni essenziali e meno critiche. React può interrompere il rendering delle parti meno critiche per un'esperienza più reattiva. Questo è ideale per il rendering di elenchi filtrati o risultati di ricerca.useOptimistic(React 19+): Mostra uno stato temporaneo e ottimistico mentre le operazioni asincrone (come le richieste di rete) sono in corso. Questo mantiene la UI reattiva anche durante il recupero dei dati (data fetching).
Suspense per il data fetching (React 18+)
Suspense in React 18 può essere usato per migliorare l'INP consentendo al browser di dare priorità alle interazioni dell'utente e ottimizzare il rendering. Mentre React 16 ha introdotto Suspense per il code splitting, React 18 estende questa funzionalità per includere il data fetching.
- Un componente di fallback, come un indicatore di caricamento, viene visualizzato mentre i dati vengono caricati.
- Una volta arrivati i dati, React riprende il rendering del componente sospeso.
- Suspense, combinato con il rendering interrompibile in Concurrent React, dà priorità alle interazioni dell'utente. Se un utente interagisce con un componente sospeso, React dà la priorità al rendering di quel componente, mantenendo la reattività.
Queste funzionalità aiutano React a dare priorità alle interazioni dell'utente rispetto al lavoro di rendering in background.
Esplora le altre fasi dell'INP
Il tempo di elaborazione è solo una parte dell'Interaction to Next Paint. Per ottimizzare completamente i tuoi punteggi INP, dovresti anche affrontare le altre due fasi:
- Input Delay: Riduci al minimo il tempo di attesa prima che i gestori di eventi inizino l'esecuzione. L'input delay rappresenta circa il 18% del tempo INP totale.
- Presentation Delay: Riduci il lavoro di rendering e aggiornamento visivo (painting) che rappresenta circa il 42% del tempo INP totale.
Per un flusso di lavoro diagnostico completo, consulta la nostra guida su come trovare e risolvere i problemi di INP, e torna alla pagina hub dell'INP per una panoramica completa.
Find out what is actually slow.
I map your critical rendering path using real field data. You get a clear answer on what blocks LCP, what causes INP spikes, and where layout shifts originate.
Book a Deep Dive
