The JavaScript runtime at a glance
See the engine, the host, and the queues in one accurate picture so the call stack, Web APIs, Node.js APIs, tasks, microtasks, and event loop fit together.
- 01Draw the runtime mapSeparate the engine’s call stack and heap from host APIs and queues.
- 02Predict basic orderingExplain why synchronous logs run before microtasks, and microtasks before timer tasks.
- 03Avoid freezing the pageUse the one-thread model to spot blocking code and chunk long work.
The runtime map
A JavaScript program does not run in empty space. It runs inside a runtime: a JavaScript engine plus the surrounding environment that gives it timers, page access, files, networking, and a way to schedule callbacks. The curriculum summary says it best: this is “the engine, the host, and the queues: one picture that explains how JavaScript runs.”
You have already met the big ingredients in earlier lessons. The Engines, runtimes & hosts lesson separated the language engine from its host. Recursion used a stack-of-plates picture for the call stack. Objects & references gave you the intuition that objects live somewhere and variables can point at them. This lesson puts those ideas on one map.
A JavaScript runtime is the engine that runs your code plus the host APIs, queues, and event loop that decide when outside work calls back into your code.
Picture one chef. The chef can cook only the order in front of them, but the restaurant has helpers: a timer can beep, a delivery driver can return, and the dining room can send a new ticket. The chef’s routine is simple: finish the current order, handle all urgent notes, then take the next ticket.
- In real life: One chef cooking the active order
- In JavaScript: The engine running one JavaScript call stack
- In real life: The order the chef is working on
- In JavaScript: The current script or function call
- In real life: The pantry
- In JavaScript: A conceptual heap where objects are kept
- In real life: Timers, delivery drivers, and dining room staff
- In JavaScript: Host APIs such as timers, fetch, DOM, or Node.js fs
- In real life: Order tickets and urgent notes
- In JavaScript: Task and microtask queues
Where the analogy stops: A restaurant is visible and tidy. A real runtime is optimized machinery; the heap sketch is conceptual, and this lesson is not a debugger for engine internals.
Keep that picture nearby. The rest of the lesson replaces each restaurant word with its runtime name.
The engine: heap & call stack
STEP THROUGHThe engine is the part that understands JavaScript. V8, SpiderMonkey, and JavaScriptCore are engines. They parse your source, create values, run expressions, call functions, and manage memory. For this map, focus on two engine-owned places:
- The call stack is the stack of currently running execution contexts. The newest call is on top, so it runs first.
- The heap is memory for objects and functions. Variables can hold references to those objects.
A stack of plates is last-in, first-out. Add a plate to the top; remove a plate from the top. The call stack behaves the same way. When one function calls another, the new call sits above the old one. The old one cannot continue until the new one returns.
- In real life: Put a plate on top
- In JavaScript: Call a function
- In real life: Take the top plate off
- In JavaScript: Return from that function
- In real life: You cannot remove the middle plate first
- In JavaScript: A caller waits while a nested call runs
Where the analogy stops: Real engines optimize aggressively, but the observable rule remains: a running function finishes or calls something else before its caller continues.
Step through the visible call stack. The newest call always runs first, then disappears when it returns.
script
console.log("start " + label); garnish(label); console.log("finish " + label);} function garnish(label) { console.log("garnish " + label);} plate("tea");console.log("ready");Notice what does not happen: the host does not need a queue for a direct function call. The call is immediate because the current line asked for it. Queues matter when work leaves the stack and comes back later.
Now add memory to the picture. The heap is where objects live; a variable can hold a reference to one of those objects. This is the same intuition from Objects & references, drawn as a small pantry box.
const chef = { name: "Mina", tickets: 1 };const alias = chef;alias.tickets = alias.tickets + 1;console.log(chef.tickets);Console: not run yet
Before the mutation, picture chef and alias as two labels pointing at one pantry box.
The sketch is deliberately labeled conceptual. Real engines use sophisticated memory layouts and garbage collectors. You do not need those internals to predict this program: both names point at the same object, so a mutation through one name is visible through the other.
The host: Web APIs & Node.js APIs
SORTThe host is the environment embedding the engine. In a browser, the host gives JavaScript access to the page, events, timers, network requests, animation frames, storage, and more. In Node.js, the host gives JavaScript access to files, processes, server sockets, timers, and its own scheduling details.
| Area | Browser host | Node.js host |
|---|---|---|
| Page or outside world | DOM objects such as document and elements | No DOM by default; server and command-line environment |
| Networking | fetch, WebSocket, browser security rules | fetch in modern Node, plus lower-level server APIs |
| Timers and frames | setTimeout, setInterval, requestAnimationFrame | setTimeout, setInterval, setImmediate |
| Files and process | Very limited direct file access | fs, process, streams, environment variables |
| Special scheduling | Tasks, microtasks, rendering checkpoints | Tasks, microtasks, plus process.nextTick as a Node-specific queue |
This boundary prevents a common mistake: assuming every global name is “JavaScript.” Array.prototype.map is language behavior; document.querySelector is a browser host API; fs.readFile is a Node.js host API. The engine runs the JavaScript you write around those calls, but the host supplies the extra capabilities.
- Call stack
- Heap for objects
console.log("hi")setTimeout(callback, 0)document.querySelector("button")2 + 3
Sort each card by who supplies the feature.
Task & microtask queues
SORTA queue holds work that is not running yet. When host work is ready to call your JavaScript, it cannot interrupt a busy stack. It waits. The two queue names to know now are:
- Task queue: larger turns such as the first script, timer callbacks, many browser events, and message events.
- Microtask queue: urgent follow-up callbacks that run after the current stack empties and before the next task. A promise
.thencallback is the one promise fact you need in this overview.
- console.log inside the current script
- setTimeout callback
- .then callback from an already settled promise
- click event handler
- queueMicrotask callback
- a regular function called by the current line
Place each callback or statement where it belongs.
Microtasks are powerful because they run soon, but they can also starve tasks if you keep adding more. Stage 6 studies promises, timers, and microtasks in depth. Here, keep the big rule: current stack first, microtasks next, one task after that.
How the event loop connects them
INTERACTIVEThe event loop is the host routine that connects the boxes. A useful browser-level simplification is: run the current task until the call stack is empty, drain the microtask queue, then take the next task. Rendering can happen between turns when the browser is able to paint.
Here is the central program for this lesson:
console.log("A");setTimeout(() => console.log("B"), 0);Promise.resolve().then(() => console.log("C"));console.log("D");The final console order is A, D, C, B. Step the model, then run the same hard-coded snippet in your browser. The page shows the actual output beside the model so the diagram stays honest.
console.log("A");setTimeout(() => console.log("B"), 0);Promise.resolve().then(() => console.log("C"));console.log("D");- script
empty
empty
empty
- A
run to compare
The script starts on the call stack. console.log("A") runs immediately.
One thread, many helpers
The phrase “JavaScript is single-threaded” usually means one JavaScript agent runs one stack of JavaScript at a time. Your current function does not share the same stack with another function running simultaneously. That is why long synchronous work freezes a page: clicks, timers, and paints have to wait.
But the host can have many helpers. Browsers use systems for timers, networking, rendering, and device events. Node.js uses the operating system and libuv; some disk and crypto operations can use libuv’s thread pool. Those helpers do not run your current JavaScript function. They eventually queue work so the engine can run a callback.
A Web Worker runs JavaScript in a separate agent with its own event loop. It can run in parallel with the page, but it communicates by messages instead of sharing the page’s call stack.
Where you’ll use this
PRACTICALRuntime thinking pays off whenever code feels “out of order.” If a log appears late, ask which queue delivered it. If a browser feature works on the page but fails in Node.js, ask whether it was a host API. If a button freezes, ask what kept the call stack busy.
function slowCount() { for (let i = 0; i < 1_000_000_000; i++) { // The stack stays busy. Clicks and paints wait. }} function chunkedCount(total) { let i = 0; function slice() { const end = Math.min(i + 10000, total); while (i < end) i++; if (i < total) setTimeout(slice, 0); } slice();}The first function is like the freeze demo from Engines, runtimes & hosts: it keeps the chef occupied. The chunked version does a slice, then uses a timer task to continue later. That gives the host chances to process input and paint between slices.
Common misconceptions
- “Zero timeout means now.” It means no intentional timer delay; the callback is still a future task.
- “Microtasks run in the middle of a function.” They wait until the current stack clears.
- “Promises are extra CPU threads.” Promise callbacks run as microtasks on the JavaScript thread.
- “The DOM is JavaScript.” The DOM is a browser host API used from JavaScript.
- “The heap sketch shows real internals.” It is a conceptual model for references.
| Mistake | Better model |
|---|---|
setTimeout(fn, 0) is immediate | It queues a task after the current stack and microtasks. |
A .then callback interrupts the current function | It waits as a microtask until the stack is empty. |
| All globals are JavaScript | Some are host APIs: document, fetch, fs, process. |
| Async means parallel JavaScript | Queued callbacks still run one at a time on their agent’s stack. |
Practice exercises
5 EXERCISESType the exact output order. Use commas or spaces between words.
console.log("start");
setTimeout(() => console.log("timer"), 0);
Promise.resolve().then(() => console.log("promise"));
queueMicrotask(() => console.log("microtask"));
console.log("end");The script prints start, queues a timer, queues two microtasks, then prints end. The microtasks print promise and microtask; the timer prints last.
On paper, make two columns: engine and host. Place each item from the starter text in the best column.
Engine: 2 + 3, call stack, object heap
Host: setTimeout, document.querySelector, fs.readFile2 + 3, the call stack, and object memory belong to the engine model. Timers, the DOM, and Node’s file system access are host APIs.
Which word prints last, and why?
console.log("before");
setTimeout(() => console.log("timer"), 0);
console.log("after");before and after print in the current script. The timer callback is queued as a task, so timer prints last.
Rewrite a long-running loop so it does not monopolize the call stack. This is the practical version of the freeze demo.
function slowCount() {
for (let i = 0; i < 1_000_000_000; i++) {
// The stack stays busy. Clicks and paints wait.
}
}
function chunkedCount(total) {
let i = 0;
function slice() {
const end = Math.min(i + 10000, total);
while (i < end) i++;
if (i < total) setTimeout(slice, 0);
}
slice();
}function chunkedCount(total) {
let i = 0;
function slice() {
const end = Math.min(i + 10000, total);
while (i < end) i++;
if (i < total) setTimeout(slice, 0);
}
slice();
}The chunked version counts in slices. Between slices, the stack clears and the browser can process input or paint.
Draw the boxes and arrows, then compare with the solution.
console.log("A");
setTimeout(() => console.log("B"), 0);
Promise.resolve().then(() => console.log("C"));
console.log("D");script task → call stack
console.log("A") → console
setTimeout(...) → host timer → task queue
Promise.then(...) → microtask queue
console.log("D") → console
microtasks drain → C
timer task runs → BA good diagram shows A and D during the script, C as the microtask, and B as the timer task.
Check your understanding
7 QUESTIONSQuestion 1 of 7Which part of the engine remembers the function calls that are running right now?
Choose an answer to see the explanation.
Question 2 of 7What does the timer snippet print?
Read the code, then predictconsole.log("A"); setTimeout(() => console.log("B"), 0); console.log("C");Choose an answer to see the explanation.
Question 3 of 7What does the promise snippet print?
Read the code, then predictconsole.log("A"); Promise.resolve().then(() => console.log("B")); console.log("C");Choose an answer to see the explanation.
Question 4 of 7After a script finishes, what does the event loop normally run before the next timer or click task?
Choose an answer to see the explanation.
Question 5 of 7Which API is supplied by Node.js rather than the JavaScript language itself?
Choose an answer to see the explanation.
Question 6 of 7Why can
setTimeout(fn, 0)still run later than a promise.thencallback?Choose an answer to see the explanation.
Question 7 of 7What does the object reference snippet print?
Read the code, then predictconst chef = { tickets: 1 }; const alias = chef; alias.tickets = 2; console.log(chef.tickets);Choose an answer to see the explanation.
Key takeaways
- The engine runs JavaScript, tracks the call stack, and manages heap memory for objects.
- The host supplies environment APIs: browser DOM, timers, fetch, animation, or Node.js fs, process, and I/O.
- Direct calls run now on the stack; timer and event callbacks wait as tasks; promise reactions wait as microtasks.
- The event loop waits for an empty stack, drains microtasks, then starts the next task.
- One JavaScript stack runs at a time, but hosts can use helpers and workers for outside work.
A JavaScript runtime is an engine plus a host: one stack of JavaScript work, memory for values, host APIs, queues, and an event loop that brings callbacks back when it is safe.
Up next: Execution contexts.