Runtime

Heap
- it stores the value of the variables, functions.
- Stores dynamic, variable-size objects.
- Slower access.
- Used for non-primitives (objects, arrays, functions).
- The references stored in the stack, but the actual object/array data lives in the heap.
Stack:
obj -> reference (pointer to heap)
arr -> reference (pointer to heap)
Heap:
{ name: "Masum" }
[1,2,3]
Callstack
- its also called
Execution Context Stack - whenever a new execution context is created(a function is invoked), it is pushed onto the stack
- when a function is completes, its execution context is popped off the stack
- Stores fixed-size, simple data.
- Fast access.
- Used for primitives and references to objects.
Stack vs Heap
Stack (fast, fixed size):
+-------+
| x = 10|
| y = 20|
| obj -> pointer to heap |
+-------+
Heap (dynamic, big):
+---------------------+
| { name: "Masum" } |
| [1,2,3] |
+---------------------+
- When you copy a primitive, a new copy is made.
- When you copy a non-primitive, the reference is copied, not the object itself.
var, let, and const don’t define where (heap or stack) a value is stored; they only define the variable’s scope and, in the case of const, the immutability of the binding. The actual storage depends on the type of value: primitives go on the stack, and objects/arrays/functions go on the heap.
Event Loop
V8 only executes JavaScript — it doesn’t include Web APIs or the event loop itself.
- In Chrome → V8 + Blink (browser runtime)
- In Node.js → V8 + libuv (event loop + async I/O)
So:
- V8 runs your JS synchronously.
- Asynchronous tasks (timers, fetch, I/O) are handled by the host environment and return results back to V8 via callback queues.
The Event Loop continuously checks:
- The Call Stack → runs synchronous code
- The Microtask Queue → runs microtasks (Promises, async/await, etc.)
- The Macrotask Queue (also called the Task Queue) → runs tasks like
setTimeout,fetch, and events
Queue
A queue is a general term for a list of tasks waiting to be executed in order (FIFO — First In, First Out).
In JavaScript:
- There are different queues for different types of asynchronous work:
- Microtask Queue
- Macrotask Queue (Task Queue)
So when people say “the queue,” they usually mean one of these two queues managed by the Event Loop.
Microtasks
Microtasks are small, high-priority asynchronous tasks that execute immediately after the current synchronous code — before the browser renders or any macrotasks run.
Promise.then(),Promise.catch(),Promise.finally()async/await(code afterawait)queueMicrotask()MutationObserver
When They Run:
After the current synchronous task finishes and before any macrotask starts.
Macrotasks
Macrotasks (also called tasks) are larger asynchronous tasks that are scheduled to run after all microtasks have finished.
setTimeout()setInterval()setImmediate()(Node.js)I/O callbacksfetch().then()(fetch callback itself is microtask)- DOM events like
clickorscroll
When They Run:
- After all synchronous code and all microtasks are completed.
- Only one macrotask runs per event loop cycle.
Combined Example
console.log("1");
setTimeout(() => console.log("2 (Macrotask)"), 0);
Promise.resolve().then(() => console.log("3 (Microtask)"));
console.log("4");
| Step | Action | Queue |
|---|---|---|
| 1 | "1" logged | Synchronous |
| 2 | setTimeout() added to Macrotask Queue | Macrotask |
| 3 | Promise.then() added to Microtask Queue | Microtask |
| 4 | "4" logged | Synchronous |
| 5 | Stack empty → run Microtask Queue | "3" logged |
| 6 | Then run Macrotask Queue | "2" logged |
The Microtask Queue and the Macrotask Queue in JavaScript are both regular FIFO (First-In, First-Out) queues in structure — but the Event Loop gives higher priority to the Microtask Queue when deciding what to execute next.