The Call Stack
To understand how JavaScript processes background tasks, you first need a quick refresher on how it processes foreground tasks using the Call Stack.
Every time a function is called, it gets added (pushed) to the top of the call stack. When the function finishes executing and returns, it gets removed (popped) off the stack.
Visualizing the Stack
Let’s look at a sequence of synchronous function calls:
function startJob() {
console.log("Job started");
workOnJob();
}
function workOnJob() {
console.log("Working on job");
finishJob();
}
function finishJob() {
console.log("Job finished");
}
startJob();
As the code executes, the call stack grows layer by layer:
[empty][startJob](Calls workOnJob)[startJob] -> [workOnJob](Calls finishJob)[startJob] -> [workOnJob] -> [finishJob]
Then, as each nested function finishes executing, it is popped off the stack in reverse order:
finishJobreturns -> pops off.workOnJobreturns -> pops off.startJobreturns -> pops off.[empty]
JavaScript’s call stack works the exact same way as any other traditional programming language. But what happens when we introduce asynchronous code? We need a secondary queue.