Call Stack vs Task Queue in JavaScript
The call stack runs code now, the task queue holds callbacks for later. Here is how they interact via the event loop.
Call Stack vs Task Queue in JavaScript
The call stack and the task queue are two sides of JavaScript's execution model. Knowing how they interact explains the order in which code runs.
The Call Stack
- Where synchronous code runs.
- LIFO. One frame active at a time.
- A function on the stack blocks everything below it.
The Task Queue (Macrotask Queue)
- Holds callbacks from
setTimeout,setInterval, I/O, UI events. - FIFO. The oldest callback is moved to the stack first.
- The event loop moves a callback from this queue to the stack only when the stack is empty.
The Microtask Queue
- Holds callbacks from
Promise.then,queueMicrotask,MutationObserver. - FIFO. The event loop drains this queue completely before touching the macrotask queue, and before rendering.
- Microtasks can starve macrotasks if you keep adding them.
Order of Execution
- Run all synchronous code on the call stack.
- When the stack is empty, drain all microtasks.
- Run one macrotask.
- Drain all microtasks generated by that macrotask.
- Render (if needed).
- Repeat from step 3.
Example
console.log("1"); setTimeout(() => console.log("2"), 0); Promise.resolve().then(() => console.log("3")); console.log("4");
Output: 1, 4, 3, 2.
1and4are synchronous.3is a microtask, runs after the stack empties.2is a macrotask, runs after all microtasks.
Why This Matters
- Promise callbacks always run before setTimeout callbacks, even with 0 delay.
- A long synchronous function delays both microtasks and macrotasks.
- An infinite chain of microtasks can freeze the page (the macrotask queue never gets a turn).
The Takeaway
The call stack runs code now. The microtask queue runs next (drained fully), then the macrotask queue runs one task at a time. The event loop moves callbacks from queues to the stack only when the stack is empty. This order explains all async timing in JS.
The call stack runs synchronous code immediately, one frame at a time. The task queue (macrotask queue) holds callbacks from setTimeout and events, waiting to run when the stack is empty.
The Promise callback. Promise.then callbacks go to the microtask queue, which the event loop drains completely before touching the macrotask queue where setTimeout callbacks live.
Microtasks (Promise.then, queueMicrotask) are drained completely before each macrotask and before rendering. Macrotasks (setTimeout, events) run one at a time, with microtasks drained after each.
Only when the call stack is empty. If a synchronous function is still running, queued callbacks wait, no matter how long the function takes.
Yes. If a microtask keeps adding more microtasks, the event loop never reaches the macrotask queue or rendering, freezing the page. Always keep microtask chains bounded.
Ready to master React completely?
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.
Master React
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course.

