completefrontend
Open lab My progress
THE JAVASCRIPT FIELD GUIDE

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.

By the end, you can
  • 01
    Draw the runtime mapTell apart the engine's call stack and heap, the host's extras, and the queues.
  • 02
    Predict the order of outputExplain why code that runs now prints first, then microtasks, then timer tasks.
  • 03
    Keep the page from freezingSpot code that keeps the call stack busy too long, and split it into small pieces.

The runtime map

Your JavaScript code never runs on its own. It always runs inside a program called a runtime. A browser is a runtime. Node.js is a runtime too. This lesson draws one map of a runtime, so you can see where each part of your code runs, and when.

A runtime has these parts:

  • The engine reads your JavaScript and runs it.
  • The host is the program around the engine, such as a browser or Node.js. It adds extras such as timers, the web page, files, and the network.
  • The queues are waiting lines. A function that should run later waits in a queue.
  • The event loop takes the next waiting function from a queue and gives it to the engine to run.

You have met some of these ideas before. The Engines, runtimes & hosts lesson showed that the engine and the host are two different programs. The Recursion lesson showed the call stack. The Objects & references lesson showed that two variables can point at one object. This lesson puts all of them on one map.

One-sentence definition

A JavaScript runtime is an engine that runs your code, plus a host that adds extras, queues where functions wait, and an event loop that decides when each waiting function runs.

A language value and a host extraPop out in the code editor (opens in a new tab)JavaScript
const price = 3;console.log(price * 2);console.log(typeof setTimeout);

Line 1 makes a variable, price, that holds 3. Line 2 multiplies it by 2 and prints 6. The engine does that work, because numbers and * are part of the JavaScript language. Line 3 uses typeof, which tells you what kind of value something is. It prints function, because the host gave the page a function called setTimeout.

A browser window is the host. Inside it, a box called engine holds the card price * 2. Next to the engine are three extras the host adds: setTimeout, document, and fetch.browser (the host)price * 2engineruns the languagesetTimeoutdocumentfetchextras the host adds
The engine runs the JavaScript language, such as price * 2. The host is the program around the engine, here a browser. It adds extras such as setTimeout, document, and fetch.
Real-life analogyThe runtime is a restaurant

Picture a restaurant with one chef. The chef can cook only one order at a time. Helpers work around the chef: a kitchen timer beeps, a delivery driver comes back, a waiter brings a new order ticket. The chef always follows the same routine. First, finish the order in front of you. Next, handle every urgent note. Then take the next order ticket.

In real life: One chef cooking one order
In JavaScript: The engine running one piece of JavaScript at a time
In real life: The order the chef is working on
In JavaScript: The script or function call running right now
In real life: The pantry where food is kept
In JavaScript: The heap, where objects are kept
In real life: Kitchen timers, delivery drivers, and waiters
In JavaScript: Host extras such as timers, fetch, the web page, or Node.js files
In real life: Order tickets and urgent notes
In JavaScript: The task queue and the microtask queue

The rest of the lesson looks at each part of the runtime in turn, with its real name.

The engine: heap & call stack

STEP THROUGH

The engine is the part that understands JavaScript. Chrome uses an engine called V8. Firefox uses SpiderMonkey. Safari uses JavaScriptCore. The engine reads your code, makes values, does the math, calls functions, and looks after memory. Two places inside the engine matter for this map:

  • The call stack is a list of the function calls that are running right now. The newest call sits on top, and the top call is the one that runs.
  • The heap is the memory where objects and functions are kept. A variable does not hold the object itself. It holds a reference, which says where the object is.
Real-life analogyThe call stack is a stack of plates

You put each new plate on top of the pile. You also take plates off from the top. So the last plate you put on is the first one you take off.

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 can't pull out a plate from the middle
In JavaScript: A function waits while the function it called runs

The call stack works the same way. When one function calls another, the new call goes on top. The first function waits. It carries on only after the new call returns.

The call stack as three stacked cards. At the bottom is script, above it plate(), and on top garnish(). The top card runs now. The two cards under it wait.new calls go on topgarnish()plate()scriptruns nowwaits for garnishwaits for plate
Each call goes on top of the call that made it. Only the top call runs. When garnish() returns, its card comes off, and plate() carries on.
Step through a nested call stack
Step 0 of 10Ready
Your turn: follow the blue line

Step through the call stack. The newest call always runs first, and it comes off the stack when it returns.

Running in
  1. script
Next: line 1
  console.log("start " + label);  garnish(label);  console.log("finish " + label);} function garnish(label) {  console.log("garnish " + label);} plate("tea");console.log("ready");
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
Pick the order name passed to plate.

A new name starts the replay again. The calls stack up the same way.

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

The replay used no queue. A plain function call runs straight away, because the current line asked for it. Queues only matter for work that should run later.

Now look at memory. Objects are kept in the heap. A variable holds a reference to an object, not a copy of it. So two variables can refer to the same object.

Two names, one object
Two names for one objectPop out in the code editor (opens in a new tab)JavaScript
const chef = { name: "Mina", tickets: 1 };const alias = chef;alias.tickets = alias.tickets + 1;console.log(chef.tickets);
The heap, simplifiedbefore line 3
chef ─┐alias ─┘
objectname: "Mina"tickets: 1

Console: not run yet

Try it yourself

Before line 3 runs, chef and alias are two names that point at one object.

A simple model of references. It doesn't show real memory.

The drawing above is a simple model, not a picture of real memory. Real engines lay out memory in more complex ways, and they clean up objects that no one uses any more. You don't need those details here. You only need one rule: both names point at the same object, so a change made through one name shows up through the other.

Assignment copies a referencePop out in the code editor (opens in a new tab)JavaScript
const cart = { items: 1 };const sameCart = cart;sameCart.items = 2;console.log(cart.items);console.log(cart === sameCart);

Line 1 makes an object with items: 1 and stores a reference to it in cart. Line 2 copies that reference into sameCart. It does not make a new object. Line 3 changes items to 2 through sameCart. Line 4 prints 2, because cart points at the same object. Line 5 prints true, because === finds that both names refer to one object.

Two name tags, cart and sameCart, both point at the same object. The object holds a card that says items: 2.cartsameCarttwo namesitems: 2objectone object
cart and sameCart are two names for one object. A change made through one name shows up through the other, because there is only one object.

If you need a real, separate copy, use structuredClone(cart). It works for plain data such as numbers, strings, arrays, and plain objects.

The host: Web APIs & Node.js APIs

SORT

The host is the program that the engine runs inside. The extras it adds are called APIs: named functions and objects your code can use. A browser's extras are called Web APIs.

  • A browser lets your code use the web page, clicks and other events, timers, network requests, and saved data.
  • Node.js lets your code use files, the running program, servers, and timers.

The table below compares the two hosts. Read each row as: "for this kind of job, a browser gives you this, and Node.js gives you that."

The same JavaScript language, with different extras from each host.
What kind of job?What a browser gives youWhat Node.js gives you
Work with a page or the outside worldThe web page, through document and its elements.No web page. It runs on servers and in the terminal.
Talk to the networkfetch and WebSocket, with the browser's safety rules.fetch in new versions, plus tools for building servers.
Run code latersetTimeout, setInterval, and requestAnimationFrame.setTimeout, setInterval, and setImmediate.
Read files and the running programAlmost no direct access to files.fs for files, process for the running program, and settings from the environment.
Decide what waits for whatTasks, microtasks, and moments to redraw the page.Tasks, microtasks, and an extra waiting line for process.nextTick.

This split helps you avoid a common mistake: thinking that every name you can use is part of JavaScript itself.

  • Array.prototype.map is part of the JavaScript language.
  • document.querySelector is a Web API from the browser.
  • fs.readFile is an API from Node.js.

The engine runs the JavaScript around those calls. The host does the extra work, such as finding an element or reading a file.

Engine or host?
  • Call stack
  • Heap for objects
  • console.log("hi")
  • setTimeout(callback, 0)
  • document.querySelector("button")
  • 2 + 3
Try it yourself
0 of 6 correct

Sort each card by who gives you the feature: the engine or the host.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Task & microtask queues

SORT

A callback is a function you hand to someone else to call later. When a timer ends, the host has a callback to run. But the engine may still be busy with other code, and the host can't interrupt it. So the callback waits in a queue, a waiting line where the first one in is the first one out. There are two queues to know:

  • The task queue holds bigger pieces of work: timer callbacks, most click and key handlers, and messages. The script itself also runs as one task.
  • The microtask queue holds small, urgent callbacks. They run as soon as the call stack is empty, before the next task.

A promise is an object that stands for a result that may arrive later. In this lesson, you only need one fact about promises: a function you pass to a promise's .then method waits in the microtask queue. The function queueMicrotask puts a callback straight into the same queue.

Microtasks can queue more microtasksPop out in the code editor (opens in a new tab)JavaScript
console.log("start");queueMicrotask(() => {  console.log("first");  queueMicrotask(() => console.log("second"));});setTimeout(() => console.log("timer"), 0);

Line 1 prints start while the script runs. Line 2 puts a callback in the microtask queue. Line 6 starts a timer, so its callback will wait in the task queue. When the script ends, the microtask runs. It prints first and queues one more microtask. That new microtask also runs before any task, so second prints before timer.

Which queue?
  • console.log in the script that is running
  • setTimeout callback
  • .then callback on a promise that has already finished
  • click event handler
  • queueMicrotask callback
  • a plain function called by the current line
Try it yourself
0 of 6 correct

Place each line or callback where it waits before it runs.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Microtasks run soon, which is useful. But if each microtask keeps adding another one, tasks never get a turn. Timers wait, and the page can't redraw. A later lesson covers promises, timers, and microtasks in depth. For now, keep one rule: first the code running now, then all microtasks, then one task.

How the event loop connects them

INTERACTIVE

The event loop is a routine the host repeats over and over. In a browser, one turn of the loop goes like this:

  1. Run one task until the call stack is empty.
  2. Run every callback in the microtask queue, until it is empty.
  3. Redraw the page, if the browser is ready to.
  4. Take the next task, and start again.

This short program shows all the parts working together:

The output-order programPop out in the code editor (opens in a new tab)JavaScript
console.log("A");setTimeout(() => console.log("B"), 0);Promise.resolve().then(() => console.log("C"));console.log("D");

It prints A, D, C, B. Lines 1 and 4 run straight away. Line 2 asks the host for a timer, whose callback will wait in the task queue. Line 3 puts a callback in the microtask queue.

Three boxes in a row. The stack box holds A, D and runs first. The microtask box holds C and runs next. The task box holds B and runs last. So the program prints A, D, C, B.prints A, D, C, BA, Dstack1. nowCmicrotask2. nextBtask3. last
A and D print while the script runs. Then the microtask prints C. Only then does the timer's task print B.

In the playground, press Step model to move the program through the map one step at a time. Then press Run in this browser. It runs the same program for real, so you can check the model against your browser.

Runtime map: one short program
console.log("A");setTimeout(() => console.log("B"), 0);Promise.resolve().then(() => console.log("C"));console.log("D");
What the model showsRun line 1
Call stack
  1. script
Host (Web APIs)

empty

Microtask queue

empty

Task queue

empty

Console in the model
  1. A
Your browser's real output

press Run to compare

Step 1 of 6Run line 1

The script starts on the call stack. console.log("A") runs straight away and prints A.

A simple model of the runtime, next to a real run of the same program in your browser. It doesn't show the inside of the real engine.

One thread, many helpers

A thread is one line of work that a computer runs step by step. People say "JavaScript is single-threaded". This means your page runs one piece of JavaScript at a time, on one call stack. Two of your functions never run at the same moment on that stack.

That is why a long piece of code freezes the page. While it runs, clicks, timers, and redraws all have to wait.

The host, though, has many helpers that work at the same time as your code:

  • A browser has helpers for timers, the network, drawing the page, and events from the mouse and keyboard.
  • Node.js uses the computer's operating system and a library called libuv. Some file and encryption work runs on extra libuv threads.

These helpers never run your JavaScript functions. When their work is done, they put a callback in a queue. Later, the engine runs that callback.

Web Workers run JavaScript in parallel

A Web Worker runs JavaScript on its own thread, with its own call stack and event loop. It can run at the same time as the page. The worker and the page don't share a call stack. They talk by sending each other messages.

Where you'll use this

PRACTICAL

The runtime map helps whenever code seems to run in the wrong order. Ask the matching question:

  • A log appears late? Ask which queue it waited in.
  • Code works in the browser but fails in Node.js? Ask whether it used a Web API.
  • A button stops responding? Ask what kept the call stack busy.
Long work versus work in small piecesPop out in the code editor (opens in a new tab)JavaScript
function slowCount() {  for (let i = 0; i < 1_000_000; i++) {    // The call stack stays busy. Clicks and redraws 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, slowCount, counts to a million in one go. Like the freeze demo in Engines, runtimes & hosts, it keeps the call stack busy the whole time.

The second function, chunkedCount, splits the work into small pieces called chunks. The inner slice function counts 10,000 more, then uses setTimeout to run the next chunk as a new task. Between chunks, the call stack is empty, so the browser can handle clicks and redraw the page.

A tiny run in chunksPop out in the code editor (opens in a new tab)JavaScript
let completed = 0;function doSlice() {  completed += 2;  console.log(completed);  if (completed < 4) setTimeout(doSlice, 0);}doSlice();

The first call to doSlice adds 2 and prints 2. Because completed is still below 4, it schedules itself again with setTimeout. The second run, as a later task, prints 4 and stops. Chunks keep the page responsive. They don't make the total work smaller, and very tiny chunks add extra waiting between them.

Common misconceptions

  • "A zero timer runs right now." Zero only means "don't add a delay". The callback still waits as a later task.
  • "Microtasks can run in the middle of a function." They wait until the call stack is empty.
  • "Promises use extra threads." A .then callback runs as a microtask, on the same thread as the rest of your JavaScript.
  • "The web page is part of JavaScript." The page, through document, is a Web API from the browser.
  • "The heap drawing shows real memory." It is a simple model that explains references.

The table below pairs each wrong idea with what really happens. Read each row from left to right.

Wrong ideas about the runtime, and what really happens.
What people thinkWhat really happens
setTimeout(fn, 0) runs fn right away.It queues a task. The task runs after the current code and all microtasks.
A .then callback can interrupt the function that is running.It waits in the microtask queue until the call stack is empty.
Every name you can use is part of JavaScript.Some come from the host, such as document, fetch, fs, and process.
Code that waits for something runs at the same time as other JavaScript.Callbacks from queues still run one at a time, on one call stack.

Practice exercises

5 EXERCISES
Exercise 1 · Warm-upPredict the order of a mixed program

Type the words in the order they print. Put commas or spaces between them.

Starter codePop out in the code editor (opens in a new tab)JavaScript
console.log("start");
setTimeout(() => console.log("timer"), 0);
Promise.resolve().then(() => console.log("promise"));
queueMicrotask(() => console.log("microtask"));
console.log("end");

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeSort features into engine or host

    On paper, make two columns: engine and host. Write each item from the starter text in the column where it belongs.

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    Engine: 2 + 3, call stack, object heap
    Host: setTimeout, document.querySelector, fs.readFile
      Exercise 3 · PracticeExplain why a zero timer isn't immediate

      Which word prints last, and why?

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      console.log("before");
      setTimeout(() => console.log("timer"), 0);
      console.log("after");

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · ChallengeStop a page from freezing by splitting the work

        Rewrite slowCount so it doesn't keep the call stack busy the whole time. Count in small pieces instead, like the demo above.

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        function slowCount() {
          for (let i = 0; i < 1_000_000; i++) {
            // The call stack stays busy. Clicks and redraws 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();
        }
          Exercise 5 · ChallengeDraw the runtime for a program

          Draw the boxes and arrows on paper, then compare your drawing with the solution.

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          console.log("A");
          setTimeout(() => console.log("B"), 0);
          Promise.resolve().then(() => console.log("C"));
          console.log("D");

            Check your understanding

            7 QUESTIONS
            Runtime overview quiz · 7 questionsScore: first tries count
            1. Question 1 of 7Which part of the engine remembers the function calls that are running right now?

              Choose an answer to see the explanation.

            2. Question 2 of 7What does this timer program print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log("A");
              setTimeout(() => console.log("B"), 0);
              console.log("C");

              Choose an answer to see the explanation.

            3. Question 3 of 7What does this promise program print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log("A");
              Promise.resolve().then(() => console.log("B"));
              console.log("C");

              Choose an answer to see the explanation.

            4. Question 4 of 7After a script finishes, what does the event loop run before the next timer or click task?

              Choose an answer to see the explanation.

            5. Question 5 of 7Which of these comes from Node.js, not from the JavaScript language?

              Choose an answer to see the explanation.

            6. Question 6 of 7Why can setTimeout(fn, 0) still run later than a promise .then callback?

              Choose an answer to see the explanation.

            7. Question 7 of 7What does this object program print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const 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 the JavaScript language. It keeps the call stack, and it keeps objects in the heap.
            • The host adds extras: the web page, timers, and fetch in a browser, or files and process in Node.js.
            • A plain function call runs right away. Timer and click callbacks wait as tasks. .then callbacks wait as microtasks.
            • The event loop waits for an empty call stack, runs every microtask, then starts the next task.
            • Your JavaScript runs one piece at a time, but the host has helpers that work at the same time.

            A JavaScript runtime is an engine plus a host. The engine runs one piece of JavaScript at a time and keeps objects in memory. The host adds extras, keeps callbacks waiting in queues, and uses the event loop to run each one when the call stack is free.

            Up next: Execution contexts.

            CompleteFrontend Clear concepts. Working examples.