Javascript Engine & Runtime

ankita srivastava
6 min readSep 16, 2023

This is a conversation between two coworkers who are working on a front-end project using Javascript.

Jill: Hey Jack, I am new to the frontend world, as I have been working on backend projects for the past few years. When I try to comprehend Javascript after working on backend projects, I am confused as to how Javascript works internally versus how the backend languages used to operate. Could you please help me understand how Javascript executes my code?

Jack: Hey, Jill, of course! Javascript is a beautiful language, and you will be amazed to see how well it manages the code internally and executes. But to understand how Javascript executes the code, you first need to know about the JS Engine, which does all these magic for us.

Jill: Ok. What is the JS Engine? Is it something similar to what other programming languages used to have, like the JVM in Java?

Jack: Yeah, somewhat similar. You can consider JS Engine as another program that is running your Javascript code. We run our source code on different browsers, and all these browsers use different JS engines to run the source code. The most famous one is Chrome’s V8 Engine, which is used by the Chrome browser and by NodeJs( using which we can build server-side applications using Javascript).

Jill: Interesting. I was not aware of this. So how does this JS engine work then?

Jack: Yes, I will tell you how the JS engine works, but before that, you need to understand the internal layout of the JS engine, which is really important.

JS Engine Internals:

Jack: You can see two things in this picture, i.e., call stack and memory heap.

  1. Call Stack: This is the place where our Javascript code gets executed, and a lot of people also call it execution context.
  2. Heap: This is the place where our code objects get stored.

Jill: You mentioned that the JS code gets executed in the execution context; how does the JS source code execution happens from start?

Jack: Ok, So let’s understand how Javascript code gets compiled first. By definition, Javascript is an interpreted language, and this was true in earlier versions of Javascript. With the evolution of modern Javascript, this has changed.

So you might be aware of:

  1. Compilation — where all the source code gets compiled at once and then can be sent for execution later on when required.

2. Interpretation — where each line gets converted to machine code and sent for execution.

3. JIT: The JS Engine does not only do compilation or interpretation. In fact, it’s a mix of both worlds. Here comes the JIT (just in time) compiler, which is a combination of compilation and interpretation in that it will compile all of the code to machine code and then immediately deliver the generated machine code for execution.

Jill: Oh, so Javascript does both things internally, and I guess this will also help in improving the performance.

Jack: Yes, but there is more. Let’s see how these things exactly happen in the JS Engine, right from the time you start the code execution.

Step 1: When you start the source code processing, parsing happens as the first step. In this step, your source code gets converted to an AST (Abstract Syntax Tree), which you can see on the right side of the above picture.

Step 2: Once the AST gets generated, the JS engine sends the AST as the output from the first step to the second step, i.e., compilation. Here, JS Engine uses the JIT compiler and generates machine code from the AST.

Step 3: Now the generated machine code is being sent to the third step, i.e., execution (which happens inside the call stack), and the machine code gets executed.

Jill: So, the simple JS code gets converted to AST, which then gets converted to machine code, and that gets executed, and we are done, right?

Jack: Not yet. Ever wondered how Javascript is so fast and smooth even though it compiles all the source code at once and gives it execution?

An intermediate phase is called as optimization. When the AST is sent to the compilation phase by the JS Engine, the JIT compiler generates the bare minimum machine code feasible and sends it to the execution phase. Javascript code runs faster this way, and then it optimizes the machine code and executes it again, making Javascript fast and seamless.

Jill: Brilliant. What a great strategy to improve performance! Can we explore or debug these steps in the browser, e.g., how parsing and other steps are happening?

Jack: Unfortunately not. Steps like parsing, compilation, and optimization happen in special threads that are not available for us to access, but the execution phase is available for us to check in the browser (the call stack and heap).

Jill: Oh nice. This is helpful to understand how JavaScript has so many steps before actually showing the result. Is this all, or do we have other parts of the browser that help the JS engine work smoothly?

Jack: Yes, you guessed it right. The JS engine is the heart of the browser for executing the source code. There are other things available inside the browser to help the JS engine, and collectively they are called the Javascript Runtime.

Jill: Great. Can you tell me a little bit about it as well.

Jack: Sure. Other than the JS Engine, the browser also has three more important parts so that the JS code works properly:

As you can see in the above image:

  1. Web API: These are the functionalities provided to the JS engine but are not available as part of the JS engine; instead, they are accessible on the window object (global object), e.g., the DOM API, Fetch API, and even the console.log that you use for printing statements is not coming from Javascript or JS Engine; instead, it’s part of this Web API and available in a window object.
  2. Callback Queue: This is the queue that holds all the callback functions from the DOM event listener, like the onClick function, until execution of that function gets triggered.
  3. Event Loop: This event loop is very important for the callback function’s execution as it takes the callback function from the callback queue and puts it in the call stack (when the call stack gets empty) for execution.

Jill: Woah. That’s a lot of information I was not aware of. I was astonished to learn that console.log, as well as the other information you gave, is not part of the JS engine. This is quite useful. So all JS runtime, including JS Engine, Web API, callback queue, and event loop, is like that, right? Are our browsers all the same?

Jack: Yes, all browsers have similar runtimes. They might use different JS engines, as I told you, Chrome uses V8 as its JS engine, but their runtime is the same. But at the same time, V8 is also getting used by NodeJs, and its runtime is a little different.

Node JS Runtime does not have a Web API as it is not a browser, and everything else, like the JS Engine, callback queue, and event loop, is the same.

Jill: Thanks Jack. That’s a lot of insights I got about Javascript internals. I learned a lot from it, and hopefully we will be catching up more often to have some more amazing and thoughtful discussions.

Jack: My pleasure. Definitely, we can catch up more often.

That concludes my discussion of the JS Engine and its runtime. I hope it will be both helpful and insightful.

--

--