scheduler.postTask(fn, { priority, signal }) queues work as 'user-blocking', 'user-visible' (default) or 'background'; a TaskController can abort it or change its priority. await scheduler.yield() lets input and rendering run mid-job, then resumes ahead of same-priority tasks, whereas setTimeout() resumes at the back of the queue. Both are Limited availability: postTask() since Chrome 94 1 , yield() since Chrome 129, both in Firefox 142 555 (August 2025), not in Safari 10 .
scheduler.postTask(() => console.log('background task'), { priority: 'background' });
scheduler.postTask(() => console.log('user-visible task'));
scheduler.postTask(() => console.log('user-blocking task'), { priority: 'user-blocking' });
const yieldToMain = () => globalThis.scheduler?.yield?.() ??
new Promise((resolve) => setTimeout(resolve)); // fallback for Safari
for (let chunk = 0, sum = 0; chunk < 20; chunk++) {
for (let i = 0; i < 3e6; i++) sum += i % 2; // a few ms of work
await yieldToMain(); // input can run here
}
console.log('20 chunks done');Output
user-blocking task 20 chunks done user-visible task background task
The yielding loop still beat the queued user-visible task. Yield at least every 50 ms to keep Interaction to Next Paint low.