Skip to main content

1.2 JS Engine and Runtime

What is a JavaScript Engine?​

A JavaScript engine is a program that reads, analyzes, and executes JavaScript code. Each browser has its own built-in JavaScript engine.

EngineBrowser/EnvironmentDeveloper
V8Chrome, Edge, Node.js, DenoGoogle
SpiderMonkeyFirefoxMozilla
JavaScriptCore (Nitro)Safari, WebKitApple
HermesReact NativeMeta

How JS Engines Work​

Let's look at the process of executing JavaScript code step by step.

Step 1: Parsing Source Code​

The engine reads text JavaScript code and splits it into tokens.

// This code
const x = 10 + 20;

// Is split into these tokens
// [const] [x] [=] [10] [+] [20] [;]

Step 2: Building the AST​

Tokens are transformed into a tree structure called an AST (Abstract Syntax Tree).

// AST for const x = 10 + 20; (simplified)
{
type: "VariableDeclaration",
kind: "const",
declarations: [{
type: "VariableDeclarator",
id: { type: "Identifier", name: "x" },
init: {
type: "BinaryExpression",
operator: "+",
left: { type: "Literal", value: 10 },
right: { type: "Literal", value: 20 }
}
}]
}

Step 3: Bytecode Generation (Interpreter)​

The AST is converted into bytecode. Bytecode is higher-level than machine code but executes faster than source code.

In the V8 engine, the Ignition interpreter handles this step.

Step 4: JIT Compilation​

When frequently executed code (Hot Code) is detected, the JIT (Just-In-Time) compiler compiles it to machine code to improve performance.

In V8, the TurboFan optimizing compiler handles this.

Source Code
↓ Parsing
AST
↓ Compilation
Bytecode ←→ Executed by Ignition interpreter
↓ Hot Code detected
Optimized Machine Code ← JIT compiled by TurboFan

V8 Engine Deep Dive​

V8 is Google's high-performance JavaScript engine, used in Chrome and Node.js.

V8 Memory Structure​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ V8 Heap Memory β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ New Space (Young Generation) β”‚ ← Newly created objects
β”‚ (1~8MB) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Old Space (Old Generation) β”‚ ← Long-lived objects
β”‚ (default max ~1.5GB) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Code Space β”‚ ← Compiled code
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Large Object Space β”‚ ← Large objects (>512KB)
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Garbage Collection​

V8 uses the Mark-and-Sweep algorithm to automatically free memory for objects that are no longer referenced.

function createData() {
// After function runs, these objects have no references β†’ GC targets
const bigArray = new Array(1000000).fill(0);
const obj = { data: bigArray };
return obj.data[0]; // Only returns the number 0
} // bigArray, obj freed by GC

let result = createData(); // 0
// result = 0, and bigArray/obj already freed

Browser Runtime​

The JavaScript engine alone cannot manipulate the DOM or make HTTP requests. It works together with Web APIs provided by the browser.

Browser Runtime Components​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Browser β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ JavaScript β”‚ β”‚ Web APIs β”‚ β”‚
β”‚ β”‚ Engine β”‚ β”‚ - DOM β”‚ β”‚
β”‚ β”‚ (V8/Spider β”‚ β”‚ - Fetch API β”‚ β”‚
β”‚ β”‚ Monkey etc) β”‚ β”‚ - setTimeout β”‚ β”‚
β”‚ β”‚ β”‚ β”‚ - Canvas API β”‚ β”‚
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ - Web Storage β”‚ β”‚
β”‚ β”‚ β”‚ Call Stackβ”‚ β”‚ β”‚ - WebSocket β”‚ β”‚
β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Event Loop + Callback Queue β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Browser-Only Global Objects​

// window object (global object in browsers)
console.log(window.innerWidth); // Browser window width
console.log(window.location.href); // Current URL

// document object (DOM access)
const btn = document.querySelector('#myBtn');
btn.addEventListener('click', () => alert('Clicked!'));

// navigator object (browser/device info)
console.log(navigator.userAgent);
console.log(navigator.language); // 'en-US'

// history object (browser history)
history.back();
history.pushState({}, '', '/new-url');

Event Loop (Brief Introduction)​

JavaScript is single-threaded but can handle asynchronous processing. The event loop manages the Call Stack and Callback Queue.

console.log('1. Start');

setTimeout(() => {
console.log('3. setTimeout callback (after 1 second)');
}, 1000);

console.log('2. End');

// Output order:
// 1. Start
// 2. End
// 3. setTimeout callback (after 1 second)

Event loop details are covered in depth in Ch6.


Node.js Runtime​

Node.js is a runtime environment that allows JavaScript to run outside of browsers. Ryan Dahl built it on top of the V8 engine in 2009.

Node.js Components​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Node.js β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ V8 Engine β”‚ β”‚ Node.js APIs β”‚ β”‚
β”‚ β”‚ β”‚ β”‚ - fs (files) β”‚ β”‚
β”‚ β”‚ JavaScript β”‚ β”‚ - http β”‚ β”‚
β”‚ β”‚ Execution β”‚ β”‚ - path β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ - os β”‚ β”‚
β”‚ β”‚ - crypto β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ libuv β”‚ β”‚
β”‚ β”‚ (Event Loop β”‚ β”‚
β”‚ β”‚ + I/O) β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Node.js-Only Features​

// File system access (not available in browsers)
import { readFileSync, writeFileSync } from 'fs';

const content = readFileSync('./data.txt', 'utf-8');
console.log(content);

writeFileSync('./output.txt', 'Hello Node.js!');

// HTTP server (not available in browsers)
import { createServer } from 'http';

const server = createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello World!');
});

server.listen(3000, () => console.log('Server running: http://localhost:3000'));

// process object (Node.js global)
console.log(process.version); // Node.js version
console.log(process.platform); // 'win32', 'linux', 'darwin'
console.log(process.env.PATH); // Environment variables

Browser vs Node.js Comparison​

ItemBrowserNode.js
Global Objectwindowglobal, globalThis
Module SystemESM (import/export)ESM + CJS (require)
DOMYesNo
File SystemNoYes
HTTP ServerNoYes
Native ModulesWeb APIsNode.js APIs
SandboxYes (security restricted)No (unrestricted)

Environment Detection with globalThis​

// Works in both browser and Node.js
if (typeof window !== 'undefined') {
console.log('Browser environment');
console.log(window.location.href);
} else {
console.log('Node.js environment');
console.log(process.version);
}

// Better approach: use globalThis
console.log(globalThis); // Browser: window, Node.js: global

Pro Tips​

Coding Patterns for V8 Optimization​

V8 uses Hidden Classes and Inline Cache techniques to optimize object access:

// Good: always initialize properties in the same order
class Point {
constructor(x, y) {
this.x = x; // always x first
this.y = y; // always y second
}
}

// Bad: dynamically adding properties (changes Hidden Class)
const p1 = {};
p1.x = 1;
p1.y = 2; // Hidden Class change β†’ de-optimization

// Maintain numeric types (V8 uses internal representations: Smi, Double, Object)
const arr = [1, 2, 3]; // Smi array (fast)
arr.push('text'); // Changes to Object array (slower)
arr.push(1.5); // Changes to Double array