The Task Queue
We know that synchronous function calls are pushed onto the Call Stack. But what happens to asynchronous callbacks when their timer finishes or their HTTP request succeeds?
Enter the Task Queue (also known as the “Message Queue” or “Macrotask Queue”).
The Golden Rule of the Event Loop
The task queue is a staging area where asynchronous callbacks wait in line to be processed. The Event Loop manages this queue with one very strict rule:
The Event Loop will ONLY push a callback from the Task Queue onto the Call Stack if the Call Stack is completely empty.
A Zero-Millisecond Delay
To prove this, look at what happens when we use setTimeout with a delay of exactly 0 milliseconds.
function startJob() {
// Pushed to the Task Queue immediately
setTimeout(() => {
console.log("Hi I'm async!");
}, 0);
console.log("Job started");
workOnJob();
}
function workOnJob() {
console.log("Working on job");
}
startJob();
Because the delay is 0, you might expect "Hi I'm async!" to print first. However, this is the actual output:
Job started
Working on job
Hi I'm async!
Why did this happen?
- The
setTimeoutinstantly pushes the callback into the Task Queue. - However,
startJobandworkOnJobare still actively running on the Call Stack. - The Event Loop sees the callback waiting, but it is strictly forbidden from interrupting the Call Stack.
- Only after
workOnJobandstartJobcompletely finish and the Call Stack becomes empty does the Event Loop move the callback onto the stack to execute.