Come fare yielding al main thread

Fare yielding al main thread per migliorare la reattività della pagina

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2026-02-07

Yield al main thread

Immagina un film romantico. L'ambientazione è un piccolo mercato francese nel centro di un piccolo villaggio. Le strade sono piene di coppie che bevono caffè, mangiano croissant e comprano fiori. Ora immagina cosa succede quando solo 1 cliente può comprare qualcosa da un venditore alla volta mentre tutti gli altri devono aspettare il proprio turno. Il panettiere viene sommerso di richieste, scoppiano discussioni dal fioraio e la romantica passeggiata si trasforma in un'attesa frustrante.

Beh... è più o meno quello che succede su un sito web quando le cose diventano troppo impegnative.

L'importanza del Yielding

Il main thread di un browser gestisce tutti i processi importanti e pianifica tutti i task importanti (parsing di HTML e CSS, esecuzione del codice JavaScript, gestione degli eventi di input come click e scroll, e il rendering visuale). 

Il main thread di un browser funziona su un modello single-threaded. Ciò significa che può eseguire solo un task alla volta. Quando un task (di solito l'esecuzione di JavaScript o il rendering) inizia a funzionare, il browser eseguirà questo task 'fino al completamento' e non si fermerà finché non sarà terminato. Ciò significa che non pianificherà né eseguirà nessun altro task finché il task precedente non sarà pronto. Questo è chiamato 'blocking the main thread'. Il blocking the main thread è un problema quando i visitatori interagiscono con una pagina perché la pagina non sarà reattiva durante il tempo di blocco. 

Un modo per risolvere il blocco del main thread è il 'Yielding al main thread'. Il yielding è una tecnica in cui i long task vengono suddivisi in più task più piccoli  per permettere al main thread di gestire task più importanti (come l'input dell'utente). 

Long task e blocking period: Quando un task impiega più di 50 millisecondi, viene classificato come long task, e qualsiasi cosa oltre quella soglia di 50 millisecondi è nota come 'blocking period' del task. Suddividere questi long task in parti più piccole permette al browser di rimanere reattivo, anche quando gestisce operazioni computazionalmente intensive.

Vecchie strategie di yielding

Prima della nuova Prioritized Task Scheduling API c'erano 4 modi per fare yielding al main thread. Tutti hanno le loro limitazioni e problematiche!

  • setTimeout(): La strategia più comune, setTimeout() funziona eseguendo il codice in una funzione callback dopo un ritardo specificato. Impostando un ritardo (o timeout) di 0, setTimeout() aggiunge il task alla fine della coda, permettendo ad altri task di essere eseguiti prima. Un problema importante è che setTimeout() non è progettato per una pianificazione precisa perché i task possono essere spostati solo alla fine della coda.
  • requestAnimationFrame(): requestAnimationFrame() funziona accodando una funzione da eseguire prima del prossimo repaint del browser. requestAnimationFrame() viene spesso combinato con setTimeout() per garantire che le funzioni callback vengano pianificate dopo il prossimo aggiornamento del layout.
  • requestIdleCallback(): Questo metodo è più adatto per task non critici e a bassa priorità che possono essere eseguiti durante i tempi di inattività del browser. Sebbene aiuti a mantenere il main thread libero per task più cruciali, requestIdleCallback() soffre di una limitazione significativa: non c'è garanzia che i task pianificati vengano eseguiti prontamente (o mai!!!), specialmente su un main thread occupato.
  • isInputPending(): isInputPending() funziona controllando gli input utente in sospeso e facendo yielding solo se viene rilevato un input. isInputPending() può essere usato insieme ad altre funzioni di yielding per prevenire yielding non necessari. Purtroppo, può restituire falsi negativi e non risponde alla necessità di fare yielding per altri task critici per le prestazioni come le animazioni.

Introduzione: scheduler.yield()

Le limitazioni di questi 4 metodi sono state una preoccupazione per il team di Chrome, specialmente con molti siti che non superano la metrica Interaction to Next Paint. Per risolvere questo problema e aiutare, il team di Chrome ha costruito una  nuova API che offre un controllo granulare sulla  pianificazione di JavaScript.

Ecco scheduler.yield()! Con window.scheduler.yield() gli sviluppatori possono effettivamente fare yielding al main thread immediatamente senza riordinare l'ordine dei task o creare complessità aggiuntiva.

Usare Scheduler.yield() efficacemente

Immergiamoci nel codice ed esploriamo come sfruttare scheduler.yield() nel modo in cui è pensato per essere usato! Prima di iniziare a usare scheduler.yield(), è importante verificare la compatibilità del browser perché è una funzionalità sperimentale e non tutti i browser la supportano ancora. 

Codice di esempio

function yieldToMain() {
  if ('scheduler' in window && 'yield' in window.scheduler) {
    return window.scheduler.yield();
  }
  return new Promise((resolve) => {
    setTimeout(resolve, 0);
  });
}

La funzione yieldToMain() è il cuore del yielding del controllo al main thread. Prima controlla che sia window.scheduler che window.scheduler.yield esistano. Se esistono possiamo usare in sicurezza window.scheduler.yield. Se  window.scheduler.yield non è supportato, il codice ricade su setTimeout().

Versione più breve e pronta per la produzione

Oppure usa questa versione più breve e pronta per la produzione che utilizza l'operatore ternario:

/* or shorter and production ready: */
function yieldToMain(){
  return"scheduler"in window&&"yield"in window.scheduler?
  window.scheduler.yield():new Promise(e=>{setTimeout(e,0)})
}

Esempio reale: Migliorare la ricerca con yieldToMain():

Vediamo come possiamo usare yieldToMain() per migliorare l'esperienza di ricerca per i tuoi utenti:

La funzione handleSearch() dimostra come yieldToMain() può essere usato efficacemente. Prima aggiorna il contenuto del pulsante per fornire un feedback immediato che una ricerca è in corso. Puoi usare yieldToMain() qui per permettere al browser di aggiornare il layout.

Successivamente, fetchData() recupera i dati di ricerca, e updateHTML(data) visualizza i risultati. Un altro  yieldToMain() assicura un rapido aggiornamento del layout (dato che non possiamo mai essere sicuri che non ci siano altri event listener in attesa dopo questo task).  Infine altri task meno importanti vengono pianificati durante il tempo di inattività del browser. Nota che non ho fatto yielding al main thread qui poiché requestIdleCallback() verrà eseguito solo quando il main thread è inattivo.

async function handleSeach(){
 /* quickly update the button content after submitting*/
 updateButtontoPending();

 /* Yield to Main */
 await yieldToMain();

 /* fetch data and update html*/
 const data = await fetchData();
 updateHTML(data);

 /* Yield to Main again */
 await yieldToMain();

 /* some function should only run during browser idle time*/
 requestIdleCallback(sendDataToAnalytics);
}

Perché scheduler.yield() è semplicemente migliore

A differenza di setTimeout(), che aggiunge i task differiti alla fine della coda dei task, scheduler.yield() mette solo in pausa la coda JavaScript e i task in pausa rimangono in testa alla coda, assicurando che vengano eseguiti il prima possibile dopo che i task a priorità più alta (come la gestione delle callback di input) sono stati completati. Questo comportamento "in testa alla coda" risolve il problema più grande dei vecchi metodi di yielding. E gli sviluppatori possono ora 'fare yielding al main thread' senza il rischio che i loro task importanti vengano ritardati da altri task meno importanti.

yielding timeline

Un altro vantaggio di scheduler.yield() è che è progettato per funzionare con la Prioritized Task Scheduling API come scheduler.postTask(), che permette di dare priorità ai task in base alla loro importanza. Questa combinazione di funzionalità fornisce agli sviluppatori un potente toolkit per ottimizzare le loro applicazioni web per reattività e prestazioni.


Come fare yielding al main threadCore Web Vitals Come fare yielding al main thread