Compile Ready
Module 1 · JavaScript Fundamentals

The JavaScript Runtime

Intermediate8m read3m practice11m total
RuntimeEvent LoopWeb APIsArchitecture

Introduction

The runtime is the engine plus everything around it that makes asynchronous, real-world programs possible: the call stack, the heap, the host's Web APIs, the callback/task queue, the microtask queue, and the event loop that ties them together.

The engine alone can only run synchronous code. The runtime is what lets setTimeout, fetch, and promises work.

Why This Matters

This is the single most important mental model in JavaScript. Almost every tricky interview question — output ordering, setTimeout(fn, 0), promise vs setTimeout, "why doesn't my UI update" — is answered by picturing the runtime correctly.

Theory

The pieces

  • Call stack — a LIFO stack of function frames. JavaScript has exactly one call stack (single-threaded).
  • Heap — unstructured memory where objects live.
  • Web APIs / host APIs — provided by the browser or Node, not the engine: setTimeout, fetch, DOM events, fs. These can do work concurrently with your code.
  • Task queue (macrotask queue) — callbacks ready to run: timer callbacks, I/O, UI events.
  • Microtask queue — higher-priority callbacks: resolved promise handlers (.then), queueMicrotask, MutationObserver.
  • Event loop — the coordinator.

The event loop algorithm (simplified)

  1. Run all synchronous code on the call stack until it is empty.
  2. Drain the entire microtask queue (running new microtasks they schedule too).
  3. Take one task from the macrotask queue and run it to completion.
  4. Drain microtasks again.
  5. (In the browser) render if needed. Repeat.

The key rule

Microtasks always run before the next macrotask. That is why a resolved Promise.then callback runs before a setTimeout(..., 0) callback scheduled at the same time.

Visual Diagrams

The runtime and the event loop
        +-------------------+        +-----------------------+
        |    Call Stack     |        |   Web / Host APIs     |
        |  (one thread)     |        | setTimeout, fetch,    |
        |                   |------->| DOM events, fs        |
        +-------------------+        +-----------+-----------+
                 ^                               | when done, enqueue callback
                 |                               v
            [ Event Loop ]  <----  Microtask queue (.then, queueMicrotask)
                 |            <----  Macrotask queue (timers, I/O, events)
                 |
   pick microtasks first (drain all), then ONE macrotask, repeat

The engine runs code on the stack; the host runs async work; the loop feeds callbacks back in.

Playground

Loading editor…
Console

Press Run to execute the code and see output here.

Output Prediction

Predict the output #1

javascript
1console.log('A');
2setTimeout(() => console.log('B'), 0);
3Promise.resolve().then(() => console.log('C'));
4console.log('D');

Interview Questions

1Explain the JavaScript runtime and the role of the event loop.

The runtime is the engine plus the call stack, heap, host Web APIs, a macrotask queue, a microtask queue, and the event loop. Synchronous code runs on the single call stack. Async operations are handed to Web APIs, which enqueue a callback when they finish. The event loop waits for the stack to empty, then drains all microtasks, then runs one macrotask, and repeats. This is how a single-threaded language handles concurrency without blocking.

Asked at:GoogleMetaAmazonMicrosoft

Follow-ups

  • Why do promises run before setTimeout?
  • What happens if a microtask schedules another microtask?

Quiz

1. Which queue does the event loop drain completely before running the next task?

Summary

  • The runtime = engine + call stack + heap + host APIs + queues + event loop.
  • There is one call stack; async work is done by host Web APIs off the stack.
  • The event loop drains all microtasks, then runs one macrotask, and repeats.
  • Microtasks (promises) always run before the next macrotask (timers, I/O).

Cheat Sheet

Runtime pieces: call stack (1), heap, Web APIs, macrotask queue, microtask queue, event loop.

Loop order: run sync → drain ALL microtasks → run ONE macrotask → repeat.

Priority: microtasks (.then, queueMicrotask) > macrotasks (setTimeout, I/O, events).

Mantra: "stack empty → microtasks → one macrotask → microtasks → …"