The call stack manages the execution of the functions being called using a last-in-first-out structure. Once a script is run, the first function is placed into the call stack. If the first function calls a second function, then that is stacked on top of it. Let’s say that the second function calls
console.log('hello world');. This would be placed on top of the second function. If there is no other functions being called, the
console.log executes and, once finished, is popped off the stack. Then the second function executes and is also popped off. Finally, the first one behaves the same way leaving the call stack to be empty. This is the single-threaded language in action.
But what happens if one of those functions took time to execute? Let’s say instead of the second function executing a
console.log, it instead performed a
console.log('Logged after a 1 second delay');
setTimeout accepts a callback function as its first argument and a number representing the delay time in milliseconds as its second argument. When it is popped off the stack and passed to the web api, the web api will set a timer based on the second argument and, once expired, passes the callback into the task queue.
The task queue operates on a first-in-first-out structure. The first function in must wait for the event loop’s permission to pass. The event loop is an algorithm constantly checking the call stack and will not let any of the callback functions into the stack until it is empty. Once it is, it will take the first callback out of the task queue and push it into the call stack allowing it to execute. Once the stack is empty again, the event loop will allow the next callback from the queue into the stack and repeat this process until the queue itself is empty.