So JavaScript, as you know, is a single-threaded language, which means it can only execute one thing at a time, and code is going to be executed sequentially, right? So when you're looking at a call stack that you have, things will get pushed onto that stack, and then they'll have to go top down to whatever's its sort of first in, first out mechanism, right? And so if you look at an example, if you've got a bunch of functions that are calling each other, the call stack kind of looks something like this. So you've got the main execution, then you go into the first function, then there's a console.log, so we can just go ahead and execute that immediately. We'll take that off of the stack, then push the second call there. Then we'll go into the second function, there's another console.log. We can execute that immediately, because it's kind of a little leaf level, so we'll get rid of that. Then we add another thing to the call stack, because we want to go into another function, so we'll go into third, console.log that, and then we can start to pop the things off of the stack, because we've reached the end of each of these functions. So one by one, we'll go through, get rid of that, and we're done.
And so when you see an error is thrown somewhere in JavaScript as well, that's where that sort of stack trace comes from. It's telling you where in the call stack of different functions that you've called, where that error is basically originating from if you go down the tree. And as you might have seen with React Native sometimes, if you do this incorrectly, it can be quite detrimental. So you can have some sort of broken code here, which calls A first, then it calls B, and B seems to call A again recursively, so you can just keep this going, and then you'll end up seeing this, right? It's all because JavaScript is single threaded. It's just because it can go through this call stack and it can only do one thing at a time, and if it keeps on going through that process in a loop, sometimes you can just block the call stack.
So then the question arises, well, it's single threaded, how do we do these long running tasks like making network calls or doing a really heavy computation? And that's where the second component of JavaScript comes in, which is that it's asynchronous, right? So despite being single threaded, JavaScript is also asynchronous, which means that if you want to handle operations like making network calls or things that could block a call stack, you can actually do that asynchronously. And that's where the event loop comes into play. So if you've got a setTimeout, which is a basic example of running an asynchronous operation with the event loop in process, if we go through the same process, we've got the main execution of the whole program, then you do a console.log for first, then you call a setTimeout. Now the setTimeout is not going to actually do anything on the call stack. Instead what it does is it goes into the browser runtime, and it says, it pushes basically a time out there, and it gets rid of that setTimeout from the call stack. So now it's running somewhere within the browser, within the JavaScript engine, and it's no longer blocking the call stack.
And so the V8 container or whatever your environment is, is in charge of waiting for that timeout to happen. So it runs some code within that environment to say, wait for two seconds here. In the meantime, I can run console.log second here. So it goes into the next one, gets rid of that. And once that timeout is done, it can push that callback that I've supplied it to the callback queue. And that's where the event loop comes into play. So the event loop checks the call stack and says, is there anything in the call stack that's currently executing? And if it is empty, what it'll do is it'll look through the callback queue and push things over up into the call stack to execute. So I've pushed back my function there, the function got a console.log, it executes that, and then it can clear the call stack. And so that's how it handles asynchronous behavior. So really the JS event loop is very simple. What it does is it checks to see if there's anything in the callback queue. And if the call stack is empty, it basically pushes all of the callbacks into your call stack and starts to execute them.
Comments