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.
| Engine | Browser/Environment | Developer |
|---|---|---|
| V8 | Chrome, Edge, Node.js, Deno | |
| SpiderMonkey | Firefox | Mozilla |
| JavaScriptCore (Nitro) | Safari, WebKit | Apple |
| Hermes | React Native | Meta |
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
| Item | Browser | Node.js |
|---|---|---|
| Global Object | window | global, globalThis |
| Module System | ESM (import/export) | ESM + CJS (require) |
| DOM | Yes | No |
| File System | No | Yes |
| HTTP Server | No | Yes |
| Native Modules | Web APIs | Node.js APIs |
| Sandbox | Yes (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