Skip to main content
Advertisement

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
Advertisement