A scheduler queues deferred callbacks and runs them after the current synchronous work finishes. In a component framework, it prevents asynchronous onMounted() work from blocking the application's first render. section 13.0
The browser event loop executes all pending microtasks, then the oldest eligible task, and finally allows the DOM to render. Microtasks therefore provide ordered, post-stack execution for lifecycle jobs. section 13.3.3 section 13.3.4
A small scheduler separates the mechanism into four responsibilities:
- Store jobs in an array with enqueueJob(job). section 13.3.4
- Schedule processJobs() with queueMicrotask() when the first job arrives. section 13.3.4
- Use isScheduled to avoid scheduling duplicate processing callbacks. section 13.3.4
- Dequeue and execute jobs in insertion order, including jobs added during processing, then reset the scheduling flag. section 13.3.5
Lifecycle integration
After creating a component DOM node, enqueue its onMounted() hook. After removing one, enqueue its onUnmounted() hook. The hooks run after mount or unmount completes and retain their scheduling order. section 13.3.6
Listing 13.3 The scheduler (scheduler.js)
let isScheduled = false #1
const jobs = [] #2
export function enqueueJob(job) {
jobs.push(job) #3
scheduleUpdate() #4
}
function scheduleUpdate() {
if (isScheduled) return
isScheduled = true
queueMicrotask(processJobs) #5
}
function processJobs() {
while (jobs.length > 0) { #6
const job = jobs.shift()
job()
}
isScheduled = false #7
}
Use the scheduler listing to inspect the complete queue, single-scheduling guard, microtask handoff, processing loop, and state reset. section 13.3.5
console.log('Start')
setTimeout(() => console.log('Timeout'))
queueMicrotask(() => console.log('Microtask 1'))
enqueueJob(() => console.log('Job'))
queueMicrotask(() => console.log('Microtask 2'))
console.log('End')
Trace console output alongside a timeout and explicit microtasks to reason about task and microtask ordering. section 13.3.5
Jobs may return promises. Wrapping each result with Promise.resolve() prevents floating promises and logs rejected jobs without interrupting the scheduler's processing loop. section 13.3.5
