Skip to content
  • How JavaScript Runs · JavaScript

How JavaScript Runs

LearnViaNotes @learnvianotes· 3 min read

Source text → tokens → AST → bytecode → optimised machine code. One call stack, one heap, and an event loop that feeds it work.

The pipeline inside V8

Source code → Parser → AST → Ignition (bytecode) → TurboFan (optimised machine code)

  1. Parse

    The source is tokenised and turned into an Abstract Syntax Tree. Syntax errors are found here — before a single line runs.

  2. Interpret

    The Ignition interpreter compiles the AST to compact bytecode and starts running it immediately (fast startup).

  3. Profile

    While running, the engine records which functions are hot and which types they see.

  4. Optimise (JIT)

    Hot functions are compiled by TurboFan (and the mid-tier Maglev) into machine code specialised for the observed types.

  5. Deoptimise

    If an assumption breaks (a function that always saw numbers suddenly gets a string), the engine throws the optimised code away and falls back to bytecode.

Memory: stack and heap

Execution contexts

Every time code runs it gets an execution context. There is one global context, plus one new context per function call. Each context is created in two phases:

PhaseWhat happens
Creation (memory)Scope is set up; var names are created as undefined, function declarations are stored in full, let/const/class names are created but uninitialised (TDZ). this is determined.
ExecutionCode runs line by line; assignments fill in the values.

The call stack in action

JavaScript
function third() {
  console.log("3. in third — stack: global → first → second → third");
}
function second() {
  console.log("2. in second");
  third();
  console.log("4. back in second");
}
function first() {
  console.log("1. in first");
  second();
  console.log("5. back in first");
}
first();
Output
1. in first
2. in second
3. in third — stack: global → first → second → third
4. back in second
5. back in first

If functions call each other without end, the stack overflows:

JavaScript
function forever(n) {
  return forever(n + 1);
}
try {
  forever(0);
} catch (e) {
  console.log(e.name + ": " + e.message);
}
Output
RangeError: Maximum call stack size exceeded

Single-threaded, yet non-blocking

JavaScript runs your code on one thread. Slow work (network, disk, timers) is handed to the runtime; when it finishes, a callback is queued and the event loop pushes it onto the stack once the stack is empty. See The Event Loop topic for the full picture.

Call stack → Runtime APIs (timers, I/O) → Task queues → Event loop → back to stack

Is JavaScript interpreted or compiled?

What is an execution context?

Free for students and teachers

Write notes like this one

Cards for every idea, quizzes and flashcards, read aloud — on the web and your phone.

Something wrong with this note? Open it to report