Search lands in PR-5.1 (Pagefind).

Explanation Intermediate

Chapter 7 Updated

Sync, Async & the magic of setTimeout(0)

Sync methods freeze the event loop, crypto can block for seconds, and setTimeout(0) still waits for the call stack.

  • Full 20m
  • Revision 5m
  • Flow 2m

Sync blocks, async offloads

V8 handles the call stack; libuv does the waiting.

  • V8 runs synchronous JS in microseconds — assignment, math, function calls on the call stack.
  • V8 cannot do async work itself — file I/O, networking, timers go to libuv.
  • Any function ending in Sync (readFileSync, writeFileSync, pbkdf2Sync) blocks the main thread.
  • Async version (same name, no Sync) → libuv thread pool or OS kernel → callback fires later.

fs.readFileSync freezes everything

The ice-cream-shop analogy.

  • While fs.readFileSync() runs, V8 is frozen — next line waits.
  • HTTP request, timers, async readFile — none of them move forward either.
  • The main thread is like a shop owner who refuses the next customer until the current one is fully served.
  • Best practice: never use Sync methods in a server’s request path.

crypto.pbkdf2Sync can block for seconds

50 million iterations on the main thread.

  • pbkdf2Sync("password", "salt", 50000000, 50, "sha512") — blocks until done.
  • Mixed sync + async order: "Hello World""First Key is Generated" → multiplication result → "Second Key is generated".
  • Async pbkdf2() offloads to libuv’s thread pool (default 4 threads) — event loop stays responsive.
  • Rule of thumb: Sync suffix = blocks; no suffix = async.

setTimeout(0) doesn't run at 0ms

The "trust issues" question.

  • Even with 0 delay, setTimeout is always async — the callback goes to libuv’s timer queue.
  • The callback runs only when the call stack is empty and the event loop reaches the timers phase.
  • All synchronous code in the GEC finishes first — always.
  • The 0 is a minimum threshold, not a guarantee.

Full execution order

Sync first, then event loop.

  • (1) All sync code runs on the call stack (V8).
  • (2) Call stack empties → the event loop takes over.
  • (3) Timer callbacks (setTimeout, setInterval) fire from the timer queue.
  • (4) I/O callbacks (async file/crypto/network) fire when libuv signals completion.
  • Sync always finishes before any async callback — even setTimeout(0).

Comments

Comments are disabled in this environment. Set PUBLIC_GISCUS_REPO, PUBLIC_GISCUS_REPO_ID, and PUBLIC_GISCUS_CATEGORY_ID to enable.