Not Now, But Next: Understanding the Macrotask Queue in JavaScript
The macrotask queue holds asynchronous tasks like timers, events, and network callbacks, which are executed by the event loop only after the current execution and all microtasks have been completed, ensuring structured and predictable scheduling.
At first, JavaScript feels immediate.
You write code.
It runs.
Line by line.
There is no visible delay.
No sense of waiting.
But then you introduce something like:
setTimeout(() => {
console.log("Later")
}, 0)And suddenly, âlaterâ doesnât mean what you expect.
It doesnât run next.
It waits.
But for what?
The Illusion of âLaterâ
When you schedule something with setTimeout, it feels like you're telling JavaScript:
âRun this after everything else.â
But thatâs not quite accurate.
What youâre actually doing is placing a task into a queue.
A very specific queue.
One that waits its turn.
The Macrotask Queue
The macrotask queue is where larger, external tasks go.
Things like:
- timers finishing
- user interactions
- network responses
They donât interrupt the current execution.
They wait.
And they only run when JavaScript is ready.
One Task at a Time
JavaScript has a single thread.
Which means:
Only one task can run at any given moment
So when a macrotask is added, it doesnât jump ahead.
It sits in line.
And the event loop decides when it gets processed.
But Thereâs a Catch
Even when the current code finishes, the macrotask doesnât run immediately.
Because thereâs another layer.
Before moving to the next macrotask, JavaScript processes all microtasks.
Promises.
Async continuations.
These run first.
Always.
Only after they are done does the macrotask get its turn.
A Subtle Ordering
This creates an execution flow that isnât obvious at first:
- run current code
- process all microtasks
- then take one macrotask
And repeat.
Which means that âlaterâ often means:
âafter everything else that is already waitingâ
Where Macrotasks Come From
Macrotasks are usually triggered by the outside world.
A user clicks.
A timer finishes.
A request completes.
These events enter JavaScript through the macrotask queue.
They are not part of the current execution.
They are arrivals.
Why This Matters
Because it changes how you think about timing.
When something feels delayed, itâs not necessarily slow.
It might just be waiting its turn.
And understanding that order helps you reason about behavior that otherwise feels unpredictable.
Rendering and Timing
Between macrotasks, the browser has a chance to update the UI.
This is why breaking heavy work into smaller tasks can improve responsiveness.
Not by making things fasterâ
but by giving the system space to breathe.
Not Just DelayâScheduling
The macrotask queue is not about postponing work randomly.
Itâs about structured scheduling.
It ensures that:
- current execution finishes cleanly
- urgent tasks (microtasks) are handled
- external events are processed in order
Everything has its place.
A Final Thought
JavaScript doesnât run things âlaterâ in a vague sense.
It runs them when the system allows.
And the macrotask queue is part of that system.
A place where work waitsâ
not indefinitely,
but until the moment is right.
Because in JavaScript, timing is not just about delay.
Itâs about order.