Gepubliceerd: 6 maart 2025
Een pagina voelt traag aan en reageert niet meer wanneer lange taken de hoofdlijn bezig houden, waardoor deze geen ander belangrijk werk kan doen, zoals reageren op gebruikersinvoer. Als gevolg hiervan kunnen zelfs ingebouwde formulierbesturingselementen er voor gebruikers kapot uitzien (alsof de pagina bevroren is), laat staan de complexere aangepaste componenten.
scheduler.yield()
is een manier om toe te geven aan de rode draad, waardoor de browser eventueel nog openstaand werk met hoge prioriteit kan uitvoeren, en vervolgens de uitvoering kan voortzetten waar het was gebleven. Hierdoor blijft een pagina responsiever en wordt de interactie met Next Paint (INP) verbeterd.
scheduler.yield
biedt een ergonomische API die precies doet wat hij zegt: de uitvoering van de functie die het wordt aangeroepen, pauzeert bij de await scheduler.yield()
expressie en gaat over op de hoofdthread, waardoor de taak wordt opgesplitst. De uitvoering van de rest van de functie (de voortzetting van de functie genoemd) wordt gepland om te worden uitgevoerd in een nieuwe gebeurtenislustaak.
async function respondToUserClick() {
giveImmediateFeedback();
await scheduler.yield(); // Yield to the main thread.
slowerComputation();
}
Het specifieke voordeel van scheduler.yield
is dat de voortzetting na de yield gepland is om te worden uitgevoerd voordat andere soortgelijke taken worden uitgevoerd die door de pagina in de wachtrij zijn geplaatst. Het geeft prioriteit aan de voortzetting van een taak boven het starten van nieuwe taken.
Functies als setTimeout
of scheduler.postTask
kunnen ook worden gebruikt om taken op te splitsen, maar deze voortzettingen worden doorgaans uitgevoerd na eventuele nieuwe taken die al in de wachtrij staan, waardoor mogelijk lange vertragingen kunnen ontstaan tussen het toegeven aan de hoofdlijn en het voltooien van hun werk.
Geef prioriteit aan voortzettingen na de bevalling
scheduler.yield
is onderdeel van de Prioritized Task Scheduling API . Als webontwikkelaars praten we doorgaans niet over de volgorde waarin de gebeurtenislus taken uitvoert in termen van expliciete prioriteiten, maar de relatieve prioriteiten zijn er altijd , zoals een requestIdleCallback
callback die wordt uitgevoerd na eventuele setTimeout
callbacks in de wachtrij, of een getriggerde invoergebeurtenislistener die gewoonlijk wordt uitgevoerd vóór een taak die in de wachtrij staat met setTimeout(callback, 0)
.
Geprioriteerde taakplanning maakt dit alleen maar explicieter, waardoor het gemakkelijker wordt om erachter te komen welke taak vóór een andere wordt uitgevoerd, en maakt het mogelijk prioriteiten aan te passen om de volgorde van uitvoering te wijzigen, indien nodig.
Zoals gezegd krijgt de voortgezette uitvoering van een functie na het opleveren met scheduler.yield()
een hogere prioriteit dan het starten van andere taken. Het leidende concept is dat eerst de voortzetting van een taak moet worden uitgevoerd, voordat met andere taken kan worden begonnen. Als de taak goed gedragen code is die periodiek wordt opgeleverd, zodat de browser andere belangrijke dingen kan doen (zoals reageren op gebruikersinvoer), mag deze niet worden gestraft voor het opleveren door voorrang te krijgen na andere soortgelijke taken.
Hier is een voorbeeld: twee functies, in de wachtrij geplaatst om in verschillende taken te worden uitgevoerd met behulp van setTimeout
.
setTimeout(myJob);
setTimeout(someoneElsesJob);
In dit geval bevinden de twee setTimeout
aanroepen zich vlak naast elkaar, maar op een echte pagina kunnen ze op totaal verschillende plaatsen worden aangeroepen, zoals een script van de eerste partij en een script van een derde partij die onafhankelijk van elkaar werk voorbereiden om uit te voeren, of het kunnen twee taken van afzonderlijke componenten zijn die diep in de planner van uw raamwerk worden geactiveerd.
Hier ziet u hoe dat werk eruit zou kunnen zien in DevTools:
myJob
wordt gemarkeerd als een lange taak, waardoor de browser niets anders kan doen terwijl deze actief is. Ervan uitgaande dat het afkomstig is van een first-party script, kunnen we het opsplitsen:
function myJob() {
// Run part 1.
myJobPart1();
// Yield with setTimeout() to break up long task, then run part2.
setTimeout(myJobPart2, 0);
}
Omdat myJobPart2
was gepland om te worden uitgevoerd met setTimeout
binnen myJob
, maar de planning wordt uitgevoerd nadat someoneElsesJob
al is gepland, ziet u hier hoe de uitvoering eruit zal zien:
We hebben de taak opgesplitst met setTimeout
, zodat de browser midden in myJob
kan reageren, maar nu wordt het tweede deel van myJob
alleen uitgevoerd nadat someoneElsesJob
klaar is.
In sommige gevallen kan dat prima zijn, maar meestal is dit niet optimaal. myJob
gaf toe aan de rode draad om ervoor te zorgen dat de pagina kon blijven reageren op gebruikersinvoer, en niet om de rode draad helemaal op te geven. In gevallen waarin someoneElsesJob
bijzonder langzaam is, of er naast someoneElsesJob
ook veel andere taken zijn gepland, kan het lang duren voordat de tweede helft van myJob
wordt uitgevoerd. Dat was waarschijnlijk niet de bedoeling van de ontwikkelaar toen ze die setTimeout
aan myJob
toevoegden.
Voer scheduler.yield()
in, waardoor de voortzetting van elke functie die deze aanroept, in een wachtrij met iets hogere prioriteit wordt geplaatst dan het starten van andere soortgelijke taken. Als myJob
wordt gewijzigd om het te gebruiken:
async function myJob() {
// Run part 1.
myJobPart1();
// Yield with scheduler.yield() to break up long task, then run part2.
await scheduler.yield();
myJobPart2();
}
Nu ziet de uitvoering er als volgt uit:
De browser heeft nog steeds de mogelijkheid om responsief te zijn, maar nu krijgt de voortzetting van de myJob
taak voorrang boven het starten van de nieuwe taak someoneElsesJob
, zodat myJob
voltooid is voordat someoneElsesJob
begint. Dit komt veel dichter in de buurt van de verwachting dat je moet toegeven aan de rode draad om het reactievermogen te behouden, en dat je de rode draad niet helemaal moet opgeven.
Prioritaire erfenis
Als onderdeel van de grotere Prioritized Task Scheduling API sluit scheduler.yield()
goed aan bij de expliciete prioriteiten die beschikbaar zijn in scheduler.postTask()
. Zonder expliciet een prioriteit ingesteld, zal een scheduler.yield()
binnen een callback scheduler.postTask()
in principe hetzelfde werken als in het vorige voorbeeld.
Als er echter een prioriteit is ingesteld, zoals het gebruik van een lage 'background'
prioriteit:
async function lowPriorityJob() {
part1();
await scheduler.yield();
part2();
}
scheduler.postTask(lowPriorityJob, {priority: 'background'});
De voortzetting zal worden gepland met een prioriteit die hoger is dan die van andere 'background'
(waarbij de verwachte geprioriteerde voortzetting wordt verkregen vóór eventuele lopende 'background'
werkzaamheden), maar nog steeds een lagere prioriteit dan andere standaardtaken of taken met hoge prioriteit; het blijft 'background'
.
Dit betekent dat als u werk met een lage prioriteit plant met een 'background'
scheduler.postTask()
(of met requestIdleCallback
), de voortzetting na een scheduler.yield()
binnenin ook zal wachten totdat de meeste andere taken zijn voltooid en de hoofdthread inactief is om te worden uitgevoerd, wat precies is wat u wilt als u rendement oplevert in een taak met lage prioriteit.
Hoe de API te gebruiken
Voorlopig is scheduler.yield()
alleen beschikbaar in op Chromium gebaseerde browsers, dus om het te gebruiken moet je een functie detecteren en terugvallen op een secundaire manier van rendement voor andere browsers.
scheduler-polyfill
is een kleine polyfill voor scheduler.postTask
en scheduler.yield
die intern een combinatie van methoden gebruikt om veel van de kracht van de plannings-API's in andere browsers te emuleren (hoewel de prioriteitsovererving scheduler.yield()
niet wordt ondersteund).
Voor degenen die een polyfill willen vermijden, is één methode om op te geven met behulp van setTimeout()
en het verlies van een geprioriteerde voortzetting te accepteren, of zelfs niet op te geven in niet-ondersteunde browsers als dat niet acceptabel is. Zie de scheduler.yield()
-documentatie in Lange taken optimaliseren voor meer informatie .
De typen wicg-task-scheduling
kunnen ook worden gebruikt om typecontrole en IDE-ondersteuning te krijgen als u de functie scheduler.yield()
detecteert en zelf een fallback toevoegt.
Meer informatie
Voor meer informatie over de API en hoe deze samenwerkt met taakprioriteiten en scheduler.postTask()
kunt u de documenten scheduler.yield()
en Prioritized Task Scheduling op MDN raadplegen.
Voor meer informatie over lange taken, hoe deze de gebruikerservaring beïnvloeden en wat u eraan kunt doen, leest u over het optimaliseren van lange taken .
,Gepubliceerd: 6 maart 2025
Een pagina voelt traag aan en reageert niet meer als lange taken de hoofdlijn bezig houden, waardoor deze geen ander belangrijk werk kan doen, zoals reageren op gebruikersinvoer. Als gevolg hiervan kunnen zelfs ingebouwde formulierbesturingselementen er voor gebruikers kapot uitzien (alsof de pagina bevroren is), laat staan de complexere aangepaste componenten.
scheduler.yield()
is een manier om toe te geven aan de rode draad, waardoor de browser eventueel nog openstaand werk met hoge prioriteit kan uitvoeren, en vervolgens de uitvoering kan voortzetten waar het was gebleven. Hierdoor blijft een pagina responsiever en wordt de interactie met Next Paint (INP) verbeterd.
scheduler.yield
biedt een ergonomische API die precies doet wat het zegt: de uitvoering van de functie die het wordt aangeroepen, pauzeert bij de await scheduler.yield()
expressie en gaat over op de hoofdthread, waardoor de taak wordt opgesplitst. De uitvoering van de rest van de functie (de voortzetting van de functie genoemd) wordt gepland om te worden uitgevoerd in een nieuwe gebeurtenislustaak.
async function respondToUserClick() {
giveImmediateFeedback();
await scheduler.yield(); // Yield to the main thread.
slowerComputation();
}
Het specifieke voordeel van scheduler.yield
is dat de voortzetting na de yield gepland is om te worden uitgevoerd voordat andere soortgelijke taken worden uitgevoerd die door de pagina in de wachtrij zijn geplaatst. Het geeft prioriteit aan de voortzetting van een taak boven het starten van nieuwe taken.
Functies als setTimeout
of scheduler.postTask
kunnen ook worden gebruikt om taken op te splitsen, maar deze voortzettingen worden doorgaans uitgevoerd na eventuele nieuwe taken die al in de wachtrij staan, waardoor mogelijk lange vertragingen kunnen ontstaan tussen het toegeven aan de hoofdlijn en het voltooien van hun werk.
Geef prioriteit aan voortzettingen na de bevalling
scheduler.yield
is onderdeel van de Prioritized Task Scheduling API . Als webontwikkelaars praten we doorgaans niet over de volgorde waarin de gebeurtenislus taken uitvoert in termen van expliciete prioriteiten, maar de relatieve prioriteiten zijn er altijd , zoals een requestIdleCallback
-callback die wordt uitgevoerd na eventuele setTimeout
-callbacks in de wachtrij, of een getriggerde invoergebeurtenislistener die gewoonlijk wordt uitgevoerd vóór een taak die in de wachtrij staat met setTimeout(callback, 0)
.
Geprioriteerde taakplanning maakt dit alleen maar explicieter, waardoor het gemakkelijker wordt om erachter te komen welke taak vóór een andere wordt uitgevoerd, en maakt het mogelijk prioriteiten aan te passen om de volgorde van uitvoering te wijzigen, indien nodig.
Zoals gezegd krijgt de voortgezette uitvoering van een functie na het opleveren met scheduler.yield()
een hogere prioriteit dan het starten van andere taken. Het leidende concept is dat eerst de voortzetting van een taak moet worden uitgevoerd, voordat met andere taken kan worden begonnen. Als de taak goed gedragen code is die periodiek wordt opgeleverd, zodat de browser andere belangrijke dingen kan doen (zoals reageren op gebruikersinvoer), mag deze niet worden gestraft voor het opleveren door voorrang te krijgen na andere soortgelijke taken.
Hier is een voorbeeld: twee functies, in de wachtrij geplaatst om in verschillende taken te worden uitgevoerd met behulp van setTimeout
.
setTimeout(myJob);
setTimeout(someoneElsesJob);
In dit geval bevinden de twee setTimeout
aanroepen zich vlak naast elkaar, maar op een echte pagina kunnen ze op totaal verschillende plaatsen worden aangeroepen, zoals een script van de eerste partij en een script van een derde partij die onafhankelijk van elkaar werk voorbereiden om uit te voeren, of het kunnen twee taken van afzonderlijke componenten zijn die diep in de planner van uw raamwerk worden geactiveerd.
Hier ziet u hoe dat werk eruit zou kunnen zien in DevTools:
myJob
wordt gemarkeerd als een lange taak, waardoor de browser niets anders kan doen terwijl deze actief is. Ervan uitgaande dat het afkomstig is van een first-party script, kunnen we het opsplitsen:
function myJob() {
// Run part 1.
myJobPart1();
// Yield with setTimeout() to break up long task, then run part2.
setTimeout(myJobPart2, 0);
}
Omdat myJobPart2
was gepland om te worden uitgevoerd met setTimeout
binnen myJob
, maar de planning wordt uitgevoerd nadat someoneElsesJob
al is gepland, ziet de uitvoering er als volgt uit:
We hebben de taak opgesplitst met setTimeout
, zodat de browser midden in myJob
kan reageren, maar nu wordt het tweede deel van myJob
alleen uitgevoerd nadat someoneElsesJob
klaar is.
In sommige gevallen kan dat prima zijn, maar meestal is dit niet optimaal. myJob
gaf toe aan de rode draad om ervoor te zorgen dat de pagina kon blijven reageren op gebruikersinvoer, en niet om de rode draad helemaal op te geven. Als someoneElsesJob
bijzonder langzaam is, of als er naast someoneElsesJob
ook veel andere taken zijn gepland, kan het lang duren voordat de tweede helft van myJob
wordt uitgevoerd. Dat was waarschijnlijk niet de bedoeling van de ontwikkelaar toen ze die setTimeout
aan myJob
toevoegden.
Voer scheduler.yield()
in, waardoor de voortzetting van elke functie die deze aanroept, in een wachtrij met iets hogere prioriteit wordt geplaatst dan het starten van andere soortgelijke taken. Als myJob
wordt gewijzigd om het te gebruiken:
async function myJob() {
// Run part 1.
myJobPart1();
// Yield with scheduler.yield() to break up long task, then run part2.
await scheduler.yield();
myJobPart2();
}
Nu ziet de uitvoering er als volgt uit:
De browser heeft nog steeds de mogelijkheid om responsief te zijn, maar nu krijgt de voortzetting van de myJob
taak voorrang boven het starten van de nieuwe taak someoneElsesJob
, zodat myJob
voltooid is voordat someoneElsesJob
begint. Dit komt veel dichter in de buurt van de verwachting dat je moet toegeven aan de rode draad om het reactievermogen te behouden, en dat je de rode draad niet helemaal moet opgeven.
Prioritaire erfenis
Als onderdeel van de grotere Prioritized Task Scheduling API sluit scheduler.yield()
goed aan bij de expliciete prioriteiten die beschikbaar zijn in scheduler.postTask()
. Zonder expliciet een prioriteit ingesteld, zal een scheduler.yield()
binnen een callback scheduler.postTask()
in principe hetzelfde werken als in het vorige voorbeeld.
Als er echter een prioriteit is ingesteld, zoals het gebruik van een lage 'background'
prioriteit:
async function lowPriorityJob() {
part1();
await scheduler.yield();
part2();
}
scheduler.postTask(lowPriorityJob, {priority: 'background'});
De voortzetting zal worden gepland met een prioriteit die hoger is dan die van andere 'background'
(waarbij de verwachte geprioriteerde voortzetting wordt verkregen vóór eventuele lopende 'background'
werkzaamheden), maar nog steeds een lagere prioriteit dan andere standaardtaken of taken met hoge prioriteit; het blijft 'background'
.
Dit betekent dat als u werk met een lage prioriteit plant met een 'background'
scheduler.postTask()
(of met requestIdleCallback
), de voortzetting na een scheduler.yield()
binnenin ook zal wachten totdat de meeste andere taken zijn voltooid en de hoofdthread inactief is om te worden uitgevoerd, wat precies is wat u wilt als u rendement oplevert in een taak met lage prioriteit.
Hoe de API te gebruiken
Voorlopig is scheduler.yield()
alleen beschikbaar in op Chromium gebaseerde browsers, dus om het te gebruiken moet je een functie detecteren en terugvallen op een secundaire manier van rendement voor andere browsers.
scheduler-polyfill
is een kleine polyfill voor scheduler.postTask
en scheduler.yield
die intern een combinatie van methoden gebruikt om veel van de kracht van de plannings-API's in andere browsers te emuleren (hoewel de prioriteitsovererving scheduler.yield()
niet wordt ondersteund).
Voor degenen die een polyfill willen vermijden, is één methode om op te geven met behulp van setTimeout()
en het verlies van een geprioriteerde voortzetting te accepteren, of zelfs niet op te geven in niet-ondersteunde browsers als dat niet acceptabel is. Zie de scheduler.yield()
-documentatie in Lange taken optimaliseren voor meer informatie .
De typen wicg-task-scheduling
kunnen ook worden gebruikt om typecontrole en IDE-ondersteuning te krijgen als u de functie scheduler.yield()
detecteert en zelf een fallback toevoegt.
Meer informatie
Voor meer informatie over de API en hoe deze samenwerkt met taakprioriteiten en scheduler.postTask()
kunt u de documenten scheduler.yield()
en Prioritized Task Scheduling op MDN raadplegen.
Voor meer informatie over lange taken, hoe deze de gebruikerservaring beïnvloeden en wat u eraan kunt doen, leest u over het optimaliseren van lange taken .
,Gepubliceerd: 6 maart 2025
Een pagina voelt traag aan en reageert niet meer wanneer lange taken de hoofdlijn bezig houden, waardoor deze geen ander belangrijk werk kan doen, zoals reageren op gebruikersinvoer. Als gevolg hiervan kunnen zelfs ingebouwde formulierbesturingselementen er voor gebruikers kapot uitzien (alsof de pagina bevroren is), laat staan de complexere aangepaste componenten.
scheduler.yield()
is een manier om toe te geven aan de rode draad, waardoor de browser eventueel nog openstaand werk met hoge prioriteit kan uitvoeren, en vervolgens de uitvoering kan voortzetten waar het was gebleven. Hierdoor blijft een pagina responsiever en wordt de interactie met Next Paint (INP) verbeterd.
scheduler.yield
biedt een ergonomische API die precies doet wat hij zegt: de uitvoering van de functie die het wordt aangeroepen, pauzeert bij de await scheduler.yield()
expressie en gaat over op de hoofdthread, waardoor de taak wordt opgesplitst. De uitvoering van de rest van de functie (de voortzetting van de functie genoemd) wordt gepland om te worden uitgevoerd in een nieuwe gebeurtenislustaak.
async function respondToUserClick() {
giveImmediateFeedback();
await scheduler.yield(); // Yield to the main thread.
slowerComputation();
}
Het specifieke voordeel van scheduler.yield
is dat de voortzetting na de yield gepland is om te worden uitgevoerd voordat andere soortgelijke taken worden uitgevoerd die door de pagina in de wachtrij zijn geplaatst. Het geeft prioriteit aan de voortzetting van een taak boven het starten van nieuwe taken.
Functies als setTimeout
of scheduler.postTask
kunnen ook worden gebruikt om taken op te splitsen, maar deze voortzettingen worden doorgaans uitgevoerd na eventuele nieuwe taken die al in de wachtrij staan, waardoor mogelijk lange vertragingen kunnen ontstaan tussen het toegeven aan de hoofdlijn en het voltooien van hun werk.
Geef prioriteit aan voortzettingen na de bevalling
scheduler.yield
is onderdeel van de Prioritized Task Scheduling API . Als webontwikkelaars praten we doorgaans niet over de volgorde waarin de gebeurtenislus taken uitvoert in termen van expliciete prioriteiten, maar de relatieve prioriteiten zijn er altijd , zoals een requestIdleCallback
callback die wordt uitgevoerd na eventuele setTimeout
callbacks in de wachtrij, of een getriggerde invoergebeurtenislistener die gewoonlijk wordt uitgevoerd vóór een taak die in de wachtrij staat met setTimeout(callback, 0)
.
Geprioriteerde taakplanning maakt dit alleen maar explicieter, waardoor het gemakkelijker wordt om erachter te komen welke taak vóór een andere wordt uitgevoerd, en maakt het mogelijk prioriteiten aan te passen om de volgorde van uitvoering te wijzigen, indien nodig.
Zoals gezegd krijgt de voortgezette uitvoering van een functie na het opleveren met scheduler.yield()
een hogere prioriteit dan het starten van andere taken. Het leidende concept is dat eerst de voortzetting van een taak moet worden uitgevoerd, voordat met andere taken kan worden begonnen. Als de taak goed gedragen code is die periodiek wordt opgeleverd, zodat de browser andere belangrijke dingen kan doen (zoals reageren op gebruikersinvoer), mag deze niet worden gestraft voor het opleveren door voorrang te krijgen na andere soortgelijke taken.
Hier is een voorbeeld: twee functies, in de wachtrij geplaatst om in verschillende taken te worden uitgevoerd met behulp van setTimeout
.
setTimeout(myJob);
setTimeout(someoneElsesJob);
In dit geval bevinden de twee setTimeout
aanroepen zich vlak naast elkaar, maar op een echte pagina kunnen ze op totaal verschillende plaatsen worden aangeroepen, zoals een script van de eerste partij en een script van een derde partij die onafhankelijk van elkaar werk voorbereiden om uit te voeren, of het kunnen twee taken van afzonderlijke componenten zijn die diep in de planner van uw raamwerk worden geactiveerd.
Hier ziet u hoe dat werk eruit zou kunnen zien in DevTools:
myJob
wordt gemarkeerd als een lange taak, waardoor de browser niets anders kan doen terwijl deze actief is. Ervan uitgaande dat het afkomstig is van een first-party script, kunnen we het opsplitsen:
function myJob() {
// Run part 1.
myJobPart1();
// Yield with setTimeout() to break up long task, then run part2.
setTimeout(myJobPart2, 0);
}
Omdat myJobPart2
was gepland om te worden uitgevoerd met setTimeout
binnen myJob
, maar de planning wordt uitgevoerd nadat someoneElsesJob
al is gepland, ziet u hier hoe de uitvoering eruit zal zien:
We hebben de taak opgesplitst met setTimeout
, zodat de browser midden in myJob
kan reageren, maar nu wordt het tweede deel van myJob
alleen uitgevoerd nadat someoneElsesJob
klaar is.
In sommige gevallen kan dat prima zijn, maar meestal is dit niet optimaal. myJob
gaf toe aan de rode draad om ervoor te zorgen dat de pagina kon blijven reageren op gebruikersinvoer, en niet om de rode draad helemaal op te geven. Als someoneElsesJob
bijzonder langzaam is, of als er naast someoneElsesJob
ook veel andere taken zijn gepland, kan het lang duren voordat de tweede helft van myJob
wordt uitgevoerd. Dat was waarschijnlijk niet de bedoeling van de ontwikkelaar toen ze die setTimeout
aan myJob
toevoegden.
Voer scheduler.yield()
in, waardoor de voortzetting van elke functie die deze aanroept, in een wachtrij met iets hogere prioriteit wordt geplaatst dan het starten van andere soortgelijke taken. Als myJob
wordt gewijzigd om het te gebruiken:
async function myJob() {
// Run part 1.
myJobPart1();
// Yield with scheduler.yield() to break up long task, then run part2.
await scheduler.yield();
myJobPart2();
}
Nu ziet de uitvoering er als volgt uit:
De browser heeft nog steeds de mogelijkheid om responsief te zijn, maar nu krijgt de voortzetting van de myJob
taak voorrang boven het starten van de nieuwe taak someoneElsesJob
, zodat myJob
voltooid is voordat someoneElsesJob
begint. Dit komt veel dichter in de buurt van de verwachting dat je moet toegeven aan de rode draad om het reactievermogen te behouden, en dat je de rode draad niet helemaal moet opgeven.
Prioritaire erfenis
Als onderdeel van de grotere Prioritized Task Scheduling API sluit scheduler.yield()
goed aan bij de expliciete prioriteiten die beschikbaar zijn in scheduler.postTask()
. Zonder expliciet een prioriteit ingesteld, zal een scheduler.yield()
binnen een callback scheduler.postTask()
in principe hetzelfde werken als in het vorige voorbeeld.
Als er echter een prioriteit is ingesteld, zoals het gebruik van een lage 'background'
prioriteit:
async function lowPriorityJob() {
part1();
await scheduler.yield();
part2();
}
scheduler.postTask(lowPriorityJob, {priority: 'background'});
De voortzetting zal worden gepland met een prioriteit die hoger is dan die van andere 'background'
(waarbij de verwachte geprioriteerde voortzetting wordt verkregen vóór eventuele lopende 'background'
werkzaamheden), maar nog steeds een lagere prioriteit dan andere standaardtaken of taken met hoge prioriteit; het blijft 'background'
.
Dit betekent dat als u werk met een lage prioriteit plant met een 'background'
scheduler.postTask()
(of met requestIdleCallback
), de voortzetting na een scheduler.yield()
binnenin ook zal wachten totdat de meeste andere taken zijn voltooid en de hoofdthread inactief is om te worden uitgevoerd, wat precies is wat u wilt als u rendement oplevert in een taak met lage prioriteit.
Hoe de API te gebruiken
Voorlopig is scheduler.yield()
alleen beschikbaar in op Chromium gebaseerde browsers, dus om het te gebruiken moet je een functie detecteren en terugvallen op een secundaire manier van rendement voor andere browsers.
scheduler-polyfill
is een kleine polyfill voor scheduler.postTask
en scheduler.yield
die intern een combinatie van methoden gebruikt om veel van de kracht van de plannings-API's in andere browsers te emuleren (hoewel de prioriteitsovererving scheduler.yield()
niet wordt ondersteund).
Voor degenen die een polyfill willen vermijden, is één methode om op te geven met behulp van setTimeout()
en het verlies van een geprioriteerde voortzetting te accepteren, of zelfs niet op te geven in niet-ondersteunde browsers als dat niet acceptabel is. Zie de scheduler.yield()
-documentatie in Lange taken optimaliseren voor meer informatie .
De typen wicg-task-scheduling
kunnen ook worden gebruikt om typecontrole en IDE-ondersteuning te krijgen als u de functie scheduler.yield()
detecteert en zelf een fallback toevoegt.
Meer informatie
Voor meer informatie over de API en hoe deze samenwerkt met taakprioriteiten en scheduler.postTask()
kunt u de documenten scheduler.yield()
en Prioritized Task Scheduling op MDN raadplegen.
Voor meer informatie over lange taken, hoe deze de gebruikerservaring beïnvloeden en wat u eraan kunt doen, leest u over het optimaliseren van lange taken .
,Gepubliceerd: 6 maart 2025
Een pagina voelt traag aan en reageert niet meer als lange taken de hoofdlijn bezig houden, waardoor deze geen ander belangrijk werk kan doen, zoals reageren op gebruikersinvoer. Als gevolg hiervan kunnen zelfs ingebouwde formulierbesturingselementen er voor gebruikers kapot uitzien (alsof de pagina bevroren is), laat staan de complexere aangepaste componenten.
scheduler.yield()
is een manier om toe te geven aan de rode draad, waardoor de browser eventueel nog openstaand werk met hoge prioriteit kan uitvoeren, en vervolgens de uitvoering kan voortzetten waar het was gebleven. Hierdoor blijft een pagina responsiever en wordt de interactie met Next Paint (INP) verbeterd.
scheduler.yield
biedt een ergonomische API die precies doet wat het zegt: de uitvoering van de functie die het wordt aangeroepen, pauzeert bij de await scheduler.yield()
expressie en gaat over op de hoofdthread, waardoor de taak wordt opgesplitst. De uitvoering van de rest van de functie (de voortzetting van de functie genoemd) wordt gepland om te worden uitgevoerd in een nieuwe gebeurtenislustaak.
async function respondToUserClick() {
giveImmediateFeedback();
await scheduler.yield(); // Yield to the main thread.
slowerComputation();
}
Het specifieke voordeel van scheduler.yield
is dat de voortzetting na de yield gepland is om te worden uitgevoerd voordat andere soortgelijke taken worden uitgevoerd die door de pagina in de wachtrij zijn geplaatst. Het geeft prioriteit aan de voortzetting van een taak boven het starten van nieuwe taken.
Functies als setTimeout
of scheduler.postTask
kunnen ook worden gebruikt om taken op te splitsen, maar deze voortzettingen worden doorgaans uitgevoerd na eventuele nieuwe taken die al in de wachtrij staan, waardoor mogelijk lange vertragingen kunnen ontstaan tussen het toegeven aan de hoofdlijn en het voltooien van hun werk.
Geef prioriteit aan voortzettingen na de bevalling
scheduler.yield
is onderdeel van de Prioritized Task Scheduling API . Als webontwikkelaars praten we doorgaans niet over de volgorde waarin de gebeurtenislus taken uitvoert in termen van expliciete prioriteiten, maar de relatieve prioriteiten zijn er altijd , zoals een requestIdleCallback
-callback die wordt uitgevoerd na eventuele setTimeout
-callbacks in de wachtrij, of een getriggerde invoergebeurtenislistener die gewoonlijk wordt uitgevoerd vóór een taak die in de wachtrij staat met setTimeout(callback, 0)
.
Geprioriteerde taakplanning maakt dit alleen maar explicieter, waardoor het gemakkelijker wordt om erachter te komen welke taak vóór een andere wordt uitgevoerd, en maakt het mogelijk prioriteiten aan te passen om de volgorde van uitvoering te wijzigen, indien nodig.
Zoals gezegd krijgt de voortgezette uitvoering van een functie na het opleveren met scheduler.yield()
een hogere prioriteit dan het starten van andere taken. Het leidende concept is dat eerst de voortzetting van een taak moet worden uitgevoerd, voordat met andere taken kan worden begonnen. Als de taak goed gedragen code is die periodiek wordt opgeleverd, zodat de browser andere belangrijke dingen kan doen (zoals reageren op gebruikersinvoer), mag deze niet worden gestraft voor het opleveren door voorrang te krijgen na andere soortgelijke taken.
Hier is een voorbeeld: twee functies, in de wachtrij geplaatst om in verschillende taken te worden uitgevoerd met behulp van setTimeout
.
setTimeout(myJob);
setTimeout(someoneElsesJob);
In dit geval bevinden de twee setTimeout
aanroepen zich vlak naast elkaar, maar op een echte pagina kunnen ze op totaal verschillende plaatsen worden aangeroepen, zoals een script van de eerste partij en een script van een derde partij die onafhankelijk van elkaar werk voorbereiden om uit te voeren, of het kunnen twee taken van afzonderlijke componenten zijn die diep in de planner van uw raamwerk worden geactiveerd.
Hier ziet u hoe dat werk eruit zou kunnen zien in DevTools:
myJob
wordt gemarkeerd als een lange taak, waardoor de browser niets anders kan doen terwijl deze actief is. Ervan uitgaande dat het afkomstig is van een first-party script, kunnen we het opsplitsen:
function myJob() {
// Run part 1.
myJobPart1();
// Yield with setTimeout() to break up long task, then run part2.
setTimeout(myJobPart2, 0);
}
Omdat myJobPart2
was gepland om te worden uitgevoerd met setTimeout
binnen myJob
, maar de planning wordt uitgevoerd nadat someoneElsesJob
al is gepland, ziet de uitvoering er als volgt uit:
We hebben de taak opgesplitst met setTimeout
, zodat de browser midden in myJob
kan reageren, maar nu wordt het tweede deel van myJob
alleen uitgevoerd nadat someoneElsesJob
klaar is.
In sommige gevallen kan dat prima zijn, maar meestal is dit niet optimaal. myJob
gaf toe aan de rode draad om ervoor te zorgen dat de pagina kon blijven reageren op gebruikersinvoer, en niet om de rode draad helemaal op te geven. Als someoneElsesJob
bijzonder langzaam is, of als er naast someoneElsesJob
ook veel andere taken zijn gepland, kan het lang duren voordat de tweede helft van myJob
wordt uitgevoerd. Dat was waarschijnlijk niet de bedoeling van de ontwikkelaar toen ze die setTimeout
aan myJob
toevoegden.
Voer scheduler.yield()
in, waardoor de voortzetting van elke functie die deze aanroept, in een wachtrij met iets hogere prioriteit wordt geplaatst dan het starten van andere soortgelijke taken. Als myJob
wordt gewijzigd om het te gebruiken:
async function myJob() {
// Run part 1.
myJobPart1();
// Yield with scheduler.yield() to break up long task, then run part2.
await scheduler.yield();
myJobPart2();
}
Nu ziet de uitvoering er als volgt uit:
De browser heeft nog steeds de mogelijkheid om responsief te zijn, maar nu krijgt de voortzetting van de myJob
taak voorrang boven het starten van de nieuwe taak someoneElsesJob
, zodat myJob
voltooid is voordat someoneElsesJob
begint. Dit komt veel dichter in de buurt van de verwachting dat je moet toegeven aan de rode draad om het reactievermogen te behouden, en dat je de rode draad niet helemaal moet opgeven.
Prioritaire erfenis
Als onderdeel van de grotere Prioritized Task Scheduling API sluit scheduler.yield()
goed aan bij de expliciete prioriteiten die beschikbaar zijn in scheduler.postTask()
. Zonder expliciet een prioriteit ingesteld, zal een scheduler.yield()
binnen een callback scheduler.postTask()
in principe hetzelfde werken als in het vorige voorbeeld.
Als er echter een prioriteit is ingesteld, zoals het gebruik van een lage 'background'
prioriteit:
async function lowPriorityJob() {
part1();
await scheduler.yield();
part2();
}
scheduler.postTask(lowPriorityJob, {priority: 'background'});
De voortzetting zal worden gepland met een prioriteit die hoger is dan die van andere 'background'
(waarbij de verwachte geprioriteerde voortzetting wordt verkregen vóór eventuele lopende 'background'
werkzaamheden), maar nog steeds een lagere prioriteit dan andere standaardtaken of taken met hoge prioriteit; het blijft 'background'
.
Dit betekent dat als u werk met een lage prioriteit plant met een 'background'
scheduler.postTask()
(of met requestIdleCallback
), de voortzetting na een scheduler.yield()
binnenin ook zal wachten totdat de meeste andere taken zijn voltooid en de hoofdthread inactief is om te worden uitgevoerd, wat precies is wat u wilt als u rendement oplevert in een taak met lage prioriteit.
Hoe de API te gebruiken
Voorlopig is scheduler.yield()
alleen beschikbaar in op Chromium gebaseerde browsers, dus om het te gebruiken moet je een functie detecteren en terugvallen op een secundaire manier van rendement voor andere browsers.
scheduler-polyfill
is een kleine polyfill voor scheduler.postTask
en scheduler.yield
die intern een combinatie van methoden gebruikt om veel van de kracht van de plannings-API's in andere browsers te emuleren (hoewel de prioriteitsovererving scheduler.yield()
niet wordt ondersteund).
Voor degenen die een polyfill willen vermijden, is één methode om op te geven met behulp van setTimeout()
en het verlies van een geprioriteerde voortzetting te accepteren, of zelfs niet op te geven in niet-ondersteunde browsers als dat niet acceptabel is. Zie de scheduler.yield()
-documentatie in Lange taken optimaliseren voor meer informatie .
De typen wicg-task-scheduling
kunnen ook worden gebruikt om typecontrole en IDE-ondersteuning te krijgen als u de functie scheduler.yield()
detecteert en zelf een fallback toevoegt.
Meer informatie
Voor meer informatie over de API en hoe deze samenwerkt met taakprioriteiten en scheduler.postTask()
kunt u de documenten scheduler.yield()
en Prioritized Task Scheduling op MDN raadplegen.
Voor meer informatie over lange taken, hoe deze de gebruikerservaring beïnvloeden en wat u eraan kunt doen, leest u over het optimaliseren van lange taken .