I've read several posts/SO threads on event loop, and according to MDN's article,
When the stack is empty, a message is taken out of the queue and processed.
As a JS novice, what I'm still confused about is -- when exactly does the call stack become "empty"? For example,
<script>
function f() {
console.log("foo");
setTimeout(g, 0);
console.log("foo again");
}
function g() {
console.log("bar");
}
function b() {
console.log("bye");
}
f();
/*<---- Is the stack empty here? */
b();
</script>
The correct order of execution is foo
- foo again
- bye
- bar
.
But today I started thinking: isn't the stack technically empty right after exiting the f()
call? I mean at that point we're not inside any function, and we haven't started any new execution, so shouldn't the setTimeout
call message (which has been immediately queued) be processed, before moving on to b()
, and giving the order of foo
- foo again
- bar
- bye
?
What if we have a million lines of code or some intensive computation to be executed and the setTimeout(func, 0)
just sits in the queue for however long?
The call stack works based on the LIFO principle i.e., last-in-first-out. When you execute a script, the JavaScript engine creates a Global Execution Context and pushes it on top of the call stack.
The event loop executes tasks from the event queue only when the call stack is empty i.e. there is no ongoing task. The event loop allows us to use callbacks and promises.
A call stack is a mechanism for an interpreter (like the JavaScript interpreter in a web browser) to keep track of its place in a script that calls multiple functions — what function is currently being run and what functions are called from within that function, etc.
The event loop checks the call stack and if the call stack is empty, it then looks to the queue. If there is anything in the queue, the event loop takes the first task and pushes it to the stack to run.
Although the block of code within the <script>
tags isn't wrapped in an explicit function, it can be helpful to think of it as being a global function that the browser tells the javascript runtime to execute. So the call stack isn't empty until the code in the script block is done executing.
When the current piece of Javascript that is executing has finished and has no more sequential instructions to execute, then and only then will the JS engine pull the next item out of the event queue.
So, in your example:
f();
b();
// JS is done executing here so this is where the next item will be
// pulled from the event queue to execute it
Javascript is single-threaded which means the current thread of Javascript runs to completion, executing all instructions within a sequence until it hits the end of the code. Then, and only then, does it pull the next item from the event queue.
Here are some other answers that may help you understand:
How Javascript Timers Work
How does JavaScript handle AJAX responses in the background? (a whole bunch of Event Loop references in this post)
Do I need to be concerned with race conditions with asynchronous Javascript?
Can JS event handlers interrupt execution of another handler?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With