The call stack is where our code is executed using something called execution context. The heap is an unstructured memory pool that stores all the objects our application needs.
We have answered where our code is executed with this look at the engine. But now the question is, how is the code compiled to machine code to be executed afterward?
We first need to make a quick computer science refresh and talk about the difference between compilation and interpretation to answer that question.
We learned that the computer's processor only understands zeros and ones in the last lecture. Therefore, every computer program must be converted into machine code, using compilation or interpretation.
In compilation, the entire source code is converted into machine code at once. This machine code is then written into a portable file that can be executed on any computer.
We have two different steps here: first, the machine code is built and then executed in the CPU .i.e in the processor. The execution can happen way after the compilation. For example, any application you're using on your computer right now has been compiled before, and you're now executing it way after its compilation.
On the other hand, in interpretation, an interpreter runs through the source code and executes it line by line. Here we do not have the same two steps as before. Instead, the code is read and executed all at the same time.
The source code still needs to be converted into machine code, but it simply happens right before it's executed and not ahead of time.
Just imagine you were using Google Maps in your browser, and you were dragging the map, and each time you dragged it would take one second for it to move. I think we can agree that it would be completely unacceptable.
This works by first splitting up each line of code into pieces that are meaningful to the language, like the
function keywords, and then saving all these pieces into the tree in a structured way. This step also checks if there are any syntax errors, and the resulting tree will later be used to generate the machine code.
const user = 'Ulrich';
Let's consider the below code and its corresponding AST
From the above, we have a variable declaration (
VariableDeclaration) which should be a constant (
kind: "const") with the name
name: "user") and value
value: "Ulrich").Besides that, there is a lot of other stuff here, as you can see. Just imagine what it would look like for a real large application. Before moving on, I want to let you know that you don't have to know what an AST looks like. This was just to let you know that it exists.
You have to keep in mind that the AST has nothing to do with the DOM tree. They are not related in any way. The AST is just a representation of our entire code inside the engine.
Then, the code is being optimized and recompiled during the already running program execution in the background. This can be done multiple times. And after each optimization, the unoptimized code is swept for the new, more optimized code without ever stopping execution.
This process is what makes modern engines such as the V8 so fast. All this parsing, compilation, and optimization happens in some special threads inside the engine that we cannot access from our code. That is, it is completely separate from the main thread that is running in the call stack executing our code.
Below is a diagram summarizing all we just said above.
or timers or even the
console.log that we use all the time.
A callback queue is a data structure contains all the callback functions that are ready to be executed.
For example, when we attach event handler functions also known as callback functions to DOM elements like a button to react to certain events, as the event happens, for example a click, the callback function will be called. Here is how that works behind the scenes.
The first thing that happens after the event is that the callback function is put into the callback queue. Then, when the stack is empty, the callback function is passed to the stack so that it can be executed.
This happens by something called the event loop (Essential for non-blocking concurrency model 👌). The event loop takes callback functions from the callback queue and puts them in the call stack to be executed.
It's pretty similar, but since we don't have a browser, we can't have the Web APIs because the browser provides these. Instead, we have multiple C++ bindings and a so-called thread pool.