Hoe je aan de main thread yieldt om de INP te verbeteren
Gebruik scheduler.yield() om long tasks op te breken en je pagina's responsief te houden.
Yield naar de main thread
Stel je een romantische film voor. Het decor is een klein Frans marktplein in het centrum van een dorpje. De straten zijn gevuld met stelletjes die koffie drinken, croissants eten en bloemen kopen. Stel je nu voor wat er gebeurt als slechts één koper tegelijk iets kan afrekenen bij een verkoper, terwijl alle anderen op hun beurt moeten wachten. De bakker wordt overspoeld met bestellingen, er breken ruzies uit bij de bloemist en de romantische wandeling verandert in een frustrerende wachtrij.
Nou ... dat is min of meer wat er gebeurt op een website als het te druk wordt.
Laatst beoordeeld door Arjen Karel in maart 2026
Waarom yielding belangrijk is voor INP
De main thread van een browser handelt alle belangrijke processen af: het parsen van HTML en CSS, het uitvoeren van JavaScript, het verwerken van input events zoals klikken en scrollen, en de visuele weergave. Hij draait op een single-threaded model. Dit betekent dat hij maar één taak tegelijk kan uitvoeren. Als een taak begint, voert de browser deze volledig uit en stopt niet voordat hij klaar is. Er wordt geen andere taak ingepland totdat de huidige taak is afgerond. Dit heet het blokkeren van de main thread.
Het blokkeren van de main thread is de hoofdoorzaak van slechte Interaction to Next Paint (INP) scores. Als een bezoeker op een knop klikt en je JavaScript blokkeert de main thread 200 milliseconden lang, kan de browser pas een reactie tekenen nadat het script klaar is. De processing time fase van INP meet precies deze vertraging. Volgens de 2025 Web Almanac is de mediane mobiele Total Blocking Time 1.916 ms. Dat is een stijging van 58% ten opzichte van vorig jaar. Dat is bijna 2 seconden waarin de browser niet kan reageren op input van de gebruiker.
Een manier om dit op te lossen is door te yielden naar de main thread. Yielding is een techniek waarbij long tasks worden opgesplitst in meerdere kleinere taken. Zo kan de browser tussendoor belangrijker werk afhandelen (zoals reageren op input van de gebruiker).
Long tasks en blocking period: Als een taak langer duurt dan 50 milliseconden, is het een long task. Alles boven die drempel van 50 milliseconden noemen we de "blocking period" van de taak. Door deze long tasks op te knippen in kleinere stukken blijft de browser responsief, zelfs bij het verwerken van zware berekeningen.
Oude yielding strategieën
Voor de komst van de Prioritized Task Scheduling API waren er 4 manieren om te yielden naar de main thread. Allemaal hebben ze hun beperkingen.
- setTimeout(): De meest gebruikte strategie.
setTimeout()met een vertraging van 0 voegt de taak toe aan het einde van de wachtrij, zodat andere taken eerst kunnen draaien. Het probleem: taken kunnen alleen naar het einde van de wachtrij worden geschoven. Andere scripts kunnen dus voorkruipen voordat jouw code verdergaat. GenestesetTimeout()aanroepen dwingen ook een minimale vertraging van 5 ms af na vijf rondes. - requestAnimationFrame(): Zet een functie in de wachtrij om uit te voeren voor de volgende repaint van de browser. Vaak gecombineerd met
setTimeout()om te zorgen dat callbacks worden ingepland na de volgende layout update. Is niet ontworpen voor yielding; is ontworpen voor animatiewerk. - requestIdleCallback(): Zeer geschikt voor niet-kritieke taken met een lage prioriteit die kunnen draaien als de browser niks te doen heeft. De beperking: er is geen garantie dat ingeplande taken snel (of überhaupt) draaien op een drukke main thread.
- isInputPending(): Controleert op openstaande input van de gebruiker en yieldt alleen als er een input wordt gedetecteerd. Google raadt deze aanpak niet meer aan. Het kan false negatives teruggeven en houdt geen rekening met ander prestatiekritiek werk zoals animaties en rendering updates.
scheduler.yield()
De beperkingen van deze methodes baarden het Chrome-team zorgen, vooral omdat veel sites falen op INP. Om dit op te lossen, bouwden ze scheduler.yield(): een nieuwe API waarmee developers direct kunnen yielden naar de main thread zonder de volgorde van taken aan te passen of complexiteit toe te voegen.
scheduler.yield() kwam stabiel uit in Chrome 129 (september 2024) en wordt nu ondersteund door alle grote browsers behalve Safari.
Codevoorbeeld
Omdat Safari scheduler.yield() nog niet ondersteunt, gebruik je een fallback naar setTimeout():
function yieldToMain() {
if ('scheduler' in window && 'yield' in window.scheduler) {
return window.scheduler.yield();
}
return new Promise((resolve) => {
setTimeout(resolve, 0);
});
} De yieldToMain() functie controleert of window.scheduler.yield bestaat. Als dat zo is, gebruikt hij de native API. Zo niet, dan valt de code terug op setTimeout(). Dit sluit aan bij het patroon dat Google aanraadt.
Voor projecten die de volledige Prioritized Task Scheduling API nodig hebben (inclusief scheduler.postTask() en TaskController), onderhoudt Google Chrome Labs een officiële polyfill.
Praktijkvoorbeeld: zoeken verbeteren met yieldToMain()
Hier is hoe yieldToMain() de zoekervaring voor je gebruikers kan verbeteren.
De handleSearch() functie updatet eerst de inhoud van de knop. Dit geeft direct feedback dat er een zoekopdracht bezig is. Daarna yieldt hij om de browser die update te laten tekenen. Vervolgens haalt fetchData() zoekgegevens op en toont updateHTML(data) de resultaten. Nog een yieldToMain() zorgt voor een snelle layout update. Ten slotte worden minder belangrijke taken ingepland als de browser niks te doen heeft. Let op: ik heb niet geyield voor requestIdleCallback(), omdat dit toch al alleen draait als de main thread idle is.
async function handleSearch() {
/* 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 functions should only run during browser idle time */
requestIdleCallback(sendDataToAnalytics);
} Kijk voor nog een praktijkvoorbeeld hoe je dit zelfde yield patroon gebruikt met dataLayer pushes. Zo voorkom je dat analytics scripts interacties blokkeren.
Waarom scheduler.yield() beter is
In tegenstelling tot setTimeout(), dat uitgestelde taken toevoegt aan het einde van de wachtrij, pauzeert scheduler.yield() de uitvoering en plaatst het vervolg aan het begin van de wachtrij. Je code gaat verder zodra werk met een hogere prioriteit (zoals het afhandelen van input callbacks) klaar is. Dit is het belangrijkste verschil: je kunt yielden naar de main thread zonder het risico dat andere scripts voorkruipen voordat je code verdergaat.

scheduler.yield() is ook ontworpen om samen te werken met de Prioritized Task Scheduling API. Als je hem aanroept binnen een scheduler.postTask() callback, neemt scheduler.yield() het prioriteitsniveau van de taak over. Deze combinatie geeft je gedetailleerde controle over hoe je JavaScript wordt geprioriteerd en wanneer het yieldt.
Browserondersteuning
scheduler.yield() wordt wereldwijd door 71,5% van de browsers ondersteund:
- Chrome 129+ en Edge 129+: stabiel sinds september 2024
- Firefox 142+: stabiel sinds augustus 2025
- Safari: niet ondersteund, geen planning aangekondigd
De setTimeout() fallback in de yieldToMain() functie hierboven zorgt ervoor dat je code in alle browsers werkt. Safari-gebruikers krijgen het oudere gedrag waarbij het vervolg achteraan de wachtrij belandt, maar de pagina yieldt nog steeds. Naarmate de browserondersteuning groeit, krijgen meer gebruikers automatisch de snellere hervatting.
Als het probleem is dat third-party scripts de main thread volledig blokkeren, is het uitstellen van die scripts een betere eerste stap dan yielding. Yielding helpt als je eigen code veel werk moet verzetten, maar je wilt dat de browser responsief blijft tussen de stukken door.
Om te verifiëren dat yielding je INP in de praktijk verbetert, monitor je je pagina's met Real User Monitoring. Lab tools zoals Lighthouse meten Total Blocking Time, maar alleen field data laat je de werkelijke INP zien die je bezoekers ervaren.
Ik lever code, geen rapport.
Ik schuif 1 of 2 sprints aan bij je team. Ik zet de monitoring op zodat je metrics groen blijven als ik weg ben.
Bel me