JS Fundamentals
How JavaScript Runs (Engines & Runtime)
Master the mechanics of JavaScript execution. Understand JS engines (V8, SpiderMonkey), execution contexts, Call Stack, Event Loop, and Runtime Environments (Browser, Node.js).
1. Introduction
To write high-performance applications, you must understand what happens when JavaScript code is run. JavaScript is a single-threaded, non-blocking asynchronous language. This behavior is enabled by the interaction between the JavaScript Engine and the surrounding Runtime Environment.
2. Why It Matters
Knowing how JavaScript runs under the hood helps you debug stack overflows, explain why asynchronous operations execute out of order, avoid blocking the main UI thread, and design optimized backend systems with Node.js.
3. Real-World Analogy
Think of a Busy Restaurant:
- The Chef (JS Engine): Can only prepare one dish at a time (Single Thread / Call Stack).
- The Paging System (Web APIs / Libuv): When an order takes time to bake, the chef starts it and hands a pager to the customer, freeing up the chef.
- The Pickup Counter (Callback Queue): Ready orders sit on the counter waiting to be taken.
- The Waiter (Event Loop): Watches the pickup counter. When the chef finishes the current dish and is free, the waiter brings the next ready order to the chef's workstation.
4. How It Works
Execution follows these structural steps:
- Parsing: The Engine parses code into an Abstract Syntax Tree (AST).
- Compilation: A JIT compiler compiles the AST into bytecode.
- Execution Contexts: A Global Execution Context is created first. Function calls push new Execution Contexts onto the Call Stack.
- Web APIs / Libuv: Async tasks (like HTTP requests, setTimeout) are delegated to the runtime.
- Callback Queue & Event Loop: Once async tasks complete, their callbacks enter the Queue. The Event Loop monitors the Call Stack. If the stack is empty, it pushes the first callback onto the stack.
5. Internal Architecture
A JavaScript Engine has two main components:
- Memory Heap: Unstructured memory allocation pool for variables and object data.
- Call Stack: LIFO (Last-In, First-Out) stack structure holding current execution contexts.
6. Visual Explanation
7. Practical Example
The following code tests your understanding of the Event Loop order of execution:
8. Common Mistakes
- Assuming setTimeout(..., 0) executes immediately: It only registers the callback with the web API host. The callback is not executed until the stack is entirely empty, meaning any blocking loops on the stack will delay the callback.
- Infinite Recursion: Calling a function recursively without a termination condition overflows the Call Stack ("RangeError: Maximum call stack size exceeded").
9. Quick Quiz
Q1: Which queue has higher execution priority: the Microtask Queue or the Macrotask (Callback) Queue?
A) Macrotask Queue
B) Microtask Queue
Answer: B — The Event Loop checks and empties the entire Microtask Queue (Promises, queueMicrotask) before picking up the next Macrotask (setTimeout, event listeners).
10. Scenario-Based Challenge
The Execution Order Predictor:
Analyze the execution flow if you chain a microtask inside a macrotask. Draw the trace of how the event loop queues up the items.
11. Debugging Exercise
Determine why the alert never pops up in a browser environment:
setTimeout(() => { alert('Task finished'); }, 100);
while (true) { // Infinite synchronous blocking loop }
View Solution
Diagnosis: The infinite while(true) loop runs synchronously on the main thread, keeping the Call Stack permanently occupied. Although the setTimeout completes after 100ms and registers its callback inside the Macrotask Queue, the Event Loop can never push the callback onto the stack because the stack is never empty. The browser tab freezes completely.
12. Interview Questions
🟢 Q1: What is Just-In-Time (JIT) compilation in modern V8 engines?
Answer: JIT compilation mixes interpretation and compilation. V8 parses code and compiles it to bytecode first. While executing the bytecode, the engine profiles the execution patterns. If a function is called repeatedly (a hot path), V8 compiles it into highly optimized machine code in the background. If execution context assumptions change later, the engine deoptimizes the code back to bytecode.
13. Production Considerations
- • Avoid Heavy Call Stacks: When designing APIs, segment huge operations with asynchronous pagination, generators, or delegate processing to background Web Workers to avoid blocking the Event Loop.