Compile Ready
Module 1 · JavaScript Fundamentals

The JavaScript Engine

Beginner8m read3m practice11m total
EngineParsingJITInternals

Introduction

A JavaScript engine is a program that reads your source code and executes it. Every browser ships one — V8 (Chrome/Edge), SpiderMonkey (Firefox), JavaScriptCore (Safari) — and Node.js embeds V8.

The engine is not the whole runtime: it executes the language, but features like setTimeout, fetch, and the DOM come from the surrounding host environment.

Why This Matters

Once you can picture the parse → compile → execute pipeline, previously "magic" behaviours become obvious: hoisting falls out of the parsing phase, JIT optimisation explains why hot loops speed up, and you can reason about performance instead of guessing.

Theory

What the engine does

  1. Parsing — the source text is tokenised and turned into an Abstract Syntax Tree (AST). Syntax errors are caught here, before any code runs.
  2. Compilation — a baseline compiler turns the AST into bytecode (V8's interpreter is called Ignition).
  3. Execution — the bytecode runs. Meanwhile a profiler watches which functions run often ("hot").
  4. Optimisation (JIT) — hot functions are recompiled to highly optimised machine code by an optimising compiler (V8's TurboFan). If an assumption breaks (e.g. a variable's type changes), the engine deoptimises back to bytecode.

Core components

  • Memory Heap — where objects and closures are allocated.
  • Call Stack — where function frames are pushed/popped as code runs.
  • Garbage Collector — reclaims memory that is no longer reachable.

Key insight: JavaScript is compiled, then interpreted, then re-compiled

Modern engines blur the line between "interpreted" and "compiled". Your code is compiled to bytecode up front and the hottest parts are JIT-compiled to native code at runtime.

Visual Diagrams

The engine pipeline
Source code
   |
   v
[ Parser ] --> AST --> [ Interpreter (Ignition) ] --> Bytecode --> Execute
                                   |                              ^
                                   | hot function?                |
                                   v                              |
                        [ Optimising compiler (TurboFan) ] -------+
                                   |  (deoptimise if assumption breaks)
                                   v
                          Optimised machine code

V8's two-tier design: fast startup via bytecode, peak speed via JIT.

Interview Questions

1Walk me through what happens when a JS engine runs a file.

The engine parses the source into tokens and an AST (catching syntax errors). A baseline compiler turns the AST into bytecode, which an interpreter executes. A profiler marks frequently-run ("hot") functions, and an optimising JIT compiler recompiles them to native machine code. If a runtime assumption is invalidated, the engine deoptimises back to bytecode. Throughout, objects live in the heap, execution uses the call stack, and a garbage collector frees unreachable memory.

Asked at:GoogleMicrosoft

Follow-ups

  • What is deoptimisation and what triggers it?
  • Where do closures live — stack or heap?
2Is JavaScript interpreted or compiled?

Both, in modern engines. Code is compiled to bytecode ahead of execution and interpreted, then hot paths are JIT-compiled to machine code at runtime. Calling JS purely "interpreted" is outdated.

Quiz

1. In V8, which component turns hot bytecode into machine code?

2. Where are objects and closures allocated?

Summary

  • An engine parses source into an AST, compiles it to bytecode, and executes it.
  • A JIT compiler recompiles hot functions to native code and can deoptimise them.
  • The engine provides the heap, the call stack, and the garbage collector.
  • V8 (Chrome/Node), SpiderMonkey (Firefox), and JavaScriptCore (Safari) are the major engines.