JavaScript Interview Prep
Asynchronous JavaScript

Web APIs & Node APIs

The Runtime's Toolbox

LinkedIn Hook

Here's a trick question interviewers love: "Is setTimeout part of JavaScript?"

Most candidates say yes. They're wrong.

setTimeout, fetch, addEventListener, geolocation, requestAnimationFrame — NONE of these are JavaScript. Open the ECMAScript spec and you won't find any of them. They are Web APIs provided by the browser. In Node.js, the equivalents are provided by a C library called libuv.

This distinction matters more than it sounds. It's the reason the same setTimeout(fn, 0) code behaves differently in Chrome, Node, and a Web Worker. It's the reason your JS engine never blocks on fetch. And it's the reason document is undefined in Node while fs is undefined in the browser.

In this lesson you'll see exactly which APIs the browser ships (timers, network, DOM, GPS, animation), which ones Node ships (libuv: fs, http, setImmediate, process.nextTick), and how both runtimes feed the same Event Loop you learned in Lesson 3.1.

Read the full lesson -> [link]

#JavaScript #WebAPIs #NodeJS #libuv #InterviewPrep #Frontend #Backend #AsyncJS


Web APIs & Node APIs thumbnail


What You'll Learn

  • Why setTimeout and fetch are NOT part of the JavaScript language
  • The common Web APIs the browser ships and which queue each one feeds
  • How Node.js replaces Web APIs with libuv and its own async primitives

Web APIs Are Not Part of JavaScript

Web APIs are not part of JavaScript itself. They are provided by the browser (or by Node.js in the form of C++ APIs). They run operations in separate threads while your JS code continues executing.

Think of Web APIs as external contractors that your company (the JS engine) hires. You hand them a task ("call me back in 2 seconds" or "fetch data from this URL"), and they do the work outside your office. When they're done, they drop the result in your mailbox (the queue).

Common Web APIs

Web APIWhat It DoesQueue It Uses
setTimeout / setIntervalTimer-based callbacksCallback Queue (Macrotask)
fetchHTTP requestsMicrotask Queue (via Promises)
DOM Event Listenersclick, scroll, keydown, etc.Callback Queue (Macrotask)
geolocationGPS/location accessCallback Queue
requestAnimationFrameAnimation frame callbacksRuns before next repaint (special)
MutationObserverDOM change observationMicrotask Queue
XMLHttpRequestLegacy HTTP requestsCallback Queue

Code Example — Multiple Web APIs

console.log("1: Synchronous");

setTimeout(() => {
  console.log("2: setTimeout (0ms)");
}, 0);

fetch("https://jsonplaceholder.typicode.com/todos/1")
  .then(() => console.log("3: fetch resolved"));

document.addEventListener("click", () => {
  console.log("4: click event");
});

console.log("5: Synchronous again");

Output (assuming no click happens):

1: Synchronous
5: Synchronous again
3: fetch resolved       <- microtask (Promise) runs first
2: setTimeout (0ms)     <- macrotask runs after microtasks

Step-by-step:

  1. "1: Synchronous" -> call stack -> prints immediately
  2. setTimeout -> handed to Web API (timer thread) -> callback goes to Callback Queue when timer completes
  3. fetch -> handed to Web API (network thread) -> when response arrives, .then callback goes to Microtask Queue
  4. addEventListener -> registered with Web API -> callback only enters queue when a click actually happens
  5. "5: Synchronous again" -> call stack -> prints immediately
  6. Call stack empty -> Event Loop checks Microtask Queue first -> fetch .then runs -> prints "3"
  7. Microtask Queue empty -> Event Loop checks Callback Queue -> setTimeout callback runs -> prints "2"

The Web API "Parking Lot"

// These all go to Web APIs — they DON'T block the call stack
setTimeout(() => console.log("timer done"), 2000);    // Timer thread
fetch("/api/data").then(res => console.log(res));     // Network thread
navigator.geolocation.getCurrentPosition(pos => {});  // Geolocation thread

console.log("I run immediately — none of the above blocks me!");

The call stack doesn't wait for any of these. It hands them off to the browser and moves on.

The Node.js Counterpart — libuv

Node.js has no browser, so it has no Web APIs. It uses libuv, a C library that provides both the event loop and a thread pool for async I/O. When you call fs.readFile, http.createServer, setImmediate, or process.nextTick, the V8 engine hands the work to libuv the same way a browser hands work to its Web APIs. Node-specific primitives include setImmediate (fires after the current I/O phase), process.nextTick (drained before microtasks), and the fs/net/http modules backed by libuv's thread pool. Same Event Loop concept, different runtime.

// Node.js — same async model, different APIs
const fs = require("fs");

console.log("1: start");

fs.readFile("./data.txt", "utf8", (err, data) => {
  console.log("3: file read done");
});

setImmediate(() => {
  console.log("4: setImmediate");
});

console.log("2: end");

The fs.readFile work is handed to libuv's thread pool; setImmediate is queued by libuv's event loop — neither blocks the call stack.

Web APIs & Node APIs visual 1


Common Mistakes

  • Saying setTimeout is a JavaScript function. It's a Web API (browser) or libuv binding (Node) — the ECMAScript spec never mentions it.
  • Assuming Node.js has access to document, window, or fetch-from-DOM. Node has its own async world backed by libuv; the fetch that shipped with Node 18+ is a Node API, not a browser one.
  • Treating requestAnimationFrame as a normal macrotask. It's a special Web API synchronized with the browser repaint cycle — not the same as setTimeout.

Interview Questions

Q: Are Web APIs part of JavaScript?

No. Web APIs (setTimeout, fetch, DOM APIs, geolocation, etc.) are provided by the browser runtime, not the JavaScript engine (V8, SpiderMonkey, etc.). In Node.js, equivalent functionality is provided by C++ APIs (like libuv for timers and I/O).

Q: What thread does setTimeout run on?

The timer for setTimeout runs on a separate browser thread (not the main JS thread). The JavaScript engine only registers the callback and moves on. When the timer completes, the browser places the callback in the Callback Queue. The Event Loop then moves it to the call stack when the stack is empty.

Q: What's the difference between requestAnimationFrame and setTimeout for animations?

requestAnimationFrame is synchronized with the browser's repaint cycle (~60fps), making animations smoother. It runs before the next repaint. setTimeout runs as a macrotask with no synchronization to rendering, which can cause janky animations. requestAnimationFrame also pauses in background tabs, saving resources.

Q: What replaces Web APIs in Node.js?

libuv. It's a C library that provides Node's event loop and a thread pool for async I/O. Node-specific async primitives like fs.readFile, http.createServer, setImmediate, and process.nextTick are implemented on top of libuv rather than browser Web APIs.


Quick Reference — Cheat Sheet

WEB APIs vs NODE APIs — QUICK MAP

Browser (Web APIs):
  setTimeout / setInterval   -> Callback Queue
  fetch                      -> Microtask Queue (Promise)
  addEventListener (DOM)     -> Callback Queue
  geolocation                -> Callback Queue
  requestAnimationFrame      -> runs before next repaint
  MutationObserver           -> Microtask Queue
  XMLHttpRequest             -> Callback Queue

Node.js (libuv-backed):
  fs.readFile / fs.writeFile -> thread pool -> Callback Queue
  http.createServer          -> libuv sockets -> Callback Queue
  setImmediate               -> check phase (after I/O)
  process.nextTick           -> drained BEFORE microtasks
  Promises / queueMicrotask  -> Microtask Queue

Rule:
  JS engine never blocks on these.
  Runtime does the work, queues the callback.

Previous: The Event Loop -> How One-Threaded JS Never Freezes Next: Callback Queue -> The Macrotask Line


This is Lesson 3.2 of the JavaScript Interview Prep Course — 14 chapters, 87 lessons.

On this page