← all labs  ·  ← prev lab  ·  next lab → (Lab 11 — not written yet)

Foundation Lab 10

Single-Threaded, Synchronous Execution

A short but load-bearing lab: JavaScript can only ever do one thing at a time. Every lab since Lab 05 has quietly relied on this — now it becomes explicit.

What this lab produces: no files, no commit — a pure concept lab. You'll run one short snippet in a console or with node.
Concept type: Common / Universal Concept
▶
EXECUTION 10 of 10
⏱
ASYNCHRONY & CONCURRENCY 9 of 10

This constraint on execution is exactly what will later shape JavaScript's entire answer to "how do we deal with waiting on something."

Mental Models

One call stack means one thing running, ever A single stack of trays with a spotlight on only the top one; no second stack exists anywhere in the diagram. running exactly one stack, always

Mental Model 1 of 5One Stack, One Active Thing, Always

Synchronous means each line fully finishes before the next starts A row of three sequential boxes, each one lighting up in turn only after the previous one fully completes. line 1 line 2 line 3

Mental Model 2 of 5Synchronous = Fully Finish, Then Advance

A long-running loop blocks everything else, including timers A busy spinning gear occupying the single thread, with a timer and a click event both waiting outside, unable to get in. busy loop timer, waiting click, waiting

Mental Model 3 of 5A Busy Loop Blocks Everything

An analogy: a single cashier with one register A single cashier serving one customer at the register, with a line of other customers waiting their turn, none served simultaneously. being served waiting in line

Mental Model 4 of 5An Analogy: One Cashier, One Register

Misconception: the word async does not create a second thread A red X over two parallel lanes, a green check over one single lane with a pause icon inserted into it. ✕ two lanes ✓ one lane, pauses

Mental Model 5 of 5Misconception: "Async" ≠ a Second Thread

Learning Objectives

  1. Objective 1 of 3 — I can state, precisely, what "single-threaded" and "synchronous" each mean, and explain that they're two related but distinct properties.
  2. Objective 2 of 3 — I can predict what happens to a scheduled timer callback while a long synchronous block is still running.
  3. Objective 3 of 3 — I can explain why the word async in JavaScript does not mean "runs on a separate thread."

Pre-Lab Quiz

Answer from intuition first.

Question 1 of 5setTimeout(fn, 0) schedules fn to run after 0 milliseconds. Does that mean fn runs immediately, interrupting whatever code is currently running?Open question

Question 2 of 5A synchronous loop takes 5 seconds to finish. During those 5 seconds, can a user's click on the page be handled?Open question

Question 3 of 5Does marking a function async cause its code to run on a separate thread from the rest of the program?Open question

Question 4 of 5Can two ordinary (non-async) JavaScript functions ever be mid-execution at the exact same instant?Open question

Question 5 of 5If a CPU-heavy synchronous loop runs inside a webpage, will the page visually freeze (no scrolling, no repainting) while it runs?Open question


The Concept

Two related but distinct words: single-threaded and synchronous

Single-threaded means there is exactly one thread — one literal sequence of instructions the CPU is following for your program — with no second thread running alongside it to pick up other work. Synchronous means each instruction fully completes before the next one begins; there's no partial overlap between one line and the next. JavaScript is both: because it's single-threaded, its normal execution has to be synchronous — with only one thread available, there's nothing else that could run concurrently with the current line anyway.

Every lab so far has already been describing this constraint

Lab 05's call stack only ever has one active context because there's only one thread to run it on. Lab 09's scope chain search happens as one uninterrupted operation, with no other code able to run partway through it. None of this was ever stated as a separate rule before now — it was the unspoken assumption underneath everything already covered.

What actually happens with something scheduled for "later"

If JavaScript can only run one thing at a time, what happens to something like a timer callback? It doesn't run early, and it doesn't interrupt whatever's currently executing — it waits until the single thread is completely free, meaning every currently-running synchronous line of code has fully finished, all the way back down to an empty call stack. Only then does the engine even consider starting something new. (The full mechanism behind exactly how that "something new" gets picked is the event loop, covered starting at Lab 41 — this lab is only about the constraint that makes an event loop necessary in the first place.)


Lab

Primary objective: confirm directly that a scheduled callback can never interrupt currently-running synchronous code, no matter how short its delay.

You'll need: a browser console or node — no project, no files.

Lab 1 of 1 — Try to interrupt the single thread

Task

Schedule a timer with a 0ms delay, then keep the thread busy, and see whether the timer can cut in line.

Instructions

Step 1 of 4

// Paste this into a scratch file or console. Read it — do not run it yet.

console.log("start");

setTimeout(function () {
  console.log("timer fired");
}, 0);

console.log("end");

This step is complete when: you've predicted the order of all three logs without running it.

Step 2 of 4

Predict the exact order the three lines print in, then reveal.

This step is complete when: you've run the snippet yourself and it matches the revealed order.

Step 3 of 4

// Edit the file yourself. Don't paste finished code — type it from these comments.

// Between the setTimeout call and the final console.log("end"),
// add a synchronous loop that takes a noticeable moment to finish:
// declare "var total = 0;", then a for loop from i = 0 to
// less than 500000000, adding i to total each time.

// Change the final console.log to also print total, e.g.
// console.log("end", total);

This step is complete when: the busy loop is added between the timer and the final log, and the final log includes total.

Step 4 of 4

Predict: does the timer callback manage to sneak in and run partway through the loop, since the loop now takes a noticeable amount of time? Run it and compare, then answer this comprehension check: if this loop ran inside an actual webpage instead of a console, what would the user visually experience while it's running, and why?


Comprehension Checklist

  • I can explain, without hand-waving, why "0ms" doesn't mean "immediately" for a timer.
  • I can predict that a long synchronous loop delays timers, clicks, and page rendering equally, since all three share the same thread.
  • I know the word async does not, by itself, create a second thread.
  • I can connect this lab's constraint to why every previous lab's call-stack model only ever has one active context.

Post-Lab Quiz

These are different questions from the pre-lab quiz — they test what the experiment should have taught you, not the same questions again.

Question 1 of 5In the busy-loop version of the experiment, did the timer callback manage to run at any point during the loop?Open question

Question 2 of 5If this loop ran inside a real webpage, what would the user experience while it's running?Open question

Question 3 of 5Suppose two setTimeout(fn, 0) calls are scheduled back to back, both before any other synchronous code runs. Can their callbacks execute at the same time as each other?Open question

Question 4 of 5Does increasing a setTimeout's delay from 0ms to, say, 5000ms change whether it can interrupt currently-running synchronous code?Open question

Question 5 of 5Given everything in this lab, what's actually wrong with the sentence "JavaScript runs the setTimeout callback in the background while the loop runs"?Open question


Reflection Questions

Write your own answer first — the blurred text is one possible answer, not the only correct one.

Reflection 1 of 3. Before this lab, if someone had asked you "does JavaScript run things in parallel," what would you have said, and why?

Reflection 2 of 3. Have you ever seen a webpage freeze up completely during some heavy operation? Reframe that experience using this lab's model — what was actually happening on the single thread at that moment?

Reflection 3 of 3. This lab said the full mechanism for "how something scheduled for later actually gets picked to run" is covered starting at Lab 41. Based only on what you know now, what's one specific question you'd want that later lab to answer?


What Breaks If This Understanding Is Wrong?

If you believe JavaScript can genuinely run two pieces of your own code at the same instant, the entire event-loop model later in this curriculum will look contradictory instead of logical — every explanation of task queues and microtasks assumes, as a starting fact, that only one thing can ever be actively running.

What JavaScript Concept Was Learned Today?

JavaScript is single-threaded and synchronous by default — exactly one thing runs at a time, and a scheduled callback can never interrupt code that's already running, no matter how short its requested delay.

Relates to: ▶ Execution (10 of 10) + ⏱ Asynchrony & Concurrency (9 of 10) — the execution constraint that makes an entire async/event-loop model necessary in the first place.


Next

That completes the Foundation section — execution contexts, the call stack, hoisting, variable declarations, the global object, the scope chain, and now the single-threaded constraint tying them all together. Lab 11 moves into Functions as a First-Class Concept, starting from an idea this section has already leaned on quietly: that a function is itself a value.

← All labs