Skip to solution
easyDSA

What is the difference between blocking and non-blocking I/O in Node.js?

432 views
01

Understand the problem

Question presented to candidate: "You need to read a file in a Node.js HTTP handler. What actually goes wrong if you use the synchronous version, and how would you prove it to a skeptical teammate?"

What a strong answer should cover:

  • Blocking I/O (e.g. fs.readFileSync) runs the operation on the main thread, synchronously — nothing else in the process, including handling other requests, can happen until it returns.
  • Non-blocking I/O (e.g. fs.readFile) hands the operation off (to libuv's thread pool for file I/O, or the OS's native async APIs for networking) and returns control immediately; the main thread keeps running other code, and a callback fires later when the result is ready.
  • The practical consequence for a server: a blocking call in a request handler does not just slow down that request — it freezes every other concurrent request and every timer for the duration, because there is only one thread running your JavaScript.
  • 📌 This is directly, measurably provable, not just a theoretical claim: run a setInterval heartbeat alongside a blocking operation and count how many times it ticks during the operation. A truly blocking call produces zero ticks during its own execution; a non-blocking equivalent lets the heartbeat keep ticking normally.
  • The "synchronous" family of Node APIs (readFileSync, execSync, synchronous crypto functions, etc.) exists deliberately for startup/CLI-script scenarios — reading config once before a server starts listening — where there is no concurrent request to protect. Using them inside a request handler is the actual anti-pattern, not the existence of the sync API itself.
  • Non-blocking I/O does not mean "faster" for a single, isolated operation, and does not always mean "faster" even in aggregate — the real, verified benefit is that the thread stays free to do other work during the wait, which only shows up under concurrent load.

Clarifying questions expected:

  • "Is this code running in a request handler that serves concurrent traffic, or a one-off startup/CLI script?" — decides whether the sync API is actually a problem here.
  • "Is the concern about this one operation's latency, or about other requests being starved while it runs?" — these are different, easily conflated problems.

Code / implementation expected: Yes — a heartbeat timer alongside both the sync and async version, with the actual tick counts, is the concrete proof, not just an assertion.

i/oblockingnon-blockingasynchronous
02

Attempt it yourself

Sketch your approach before reading the solution — that's what interviews test.

Nudge consolestandby

Stuck? Beam a request up — the console returns a conceptual nudge that guides your logic without spoiling the implementation.

03

Study the solution

Target Audience: Engineers preparing for Node.js interviews — assumes basic fs module and event-loop familiarity. Difficulty: Easy

How to read this doc: Concepts are explained in plain language first, then tagged with 📌 Interview term:. The tick counts and timings below came from **actual

Solution ready — 2 min read

Classified // press E to declassify

04

Read the code

A 10ms heartbeat proves readFileSync freezes the loop (0 ticks) while readFile does not (12 ticks)
const fs = require("node:fs");
const BIG = "big.bin"; // a real 50MB file on disk

let ticks = 0;
const heartbeat = setInterval(() => ticks++, 10);

const t0 = Date.now();
for (let i = 0; i < 15; i++) fs.readFileSync(BIG);
console.log(`readFileSync x15 took ${Date.now() - t0}ms; ticks during it: ${ticks}`);
// readFileSync x15 (50MB each) took 360ms wall time; heartbeat ticked 0 times DURING it

const before = ticks;
const t1 = Date.now();
let done = 0;
for (let i = 0; i < 15; i++) {
  fs.readFile(BIG, () => {
    if (++done === 15) {
      console.log(`fs.readFile x15 took ${Date.now() - t1}ms; ticks during it: ${ticks - before}`);
      clearInterval(heartbeat);
    }
  });
}
// fs.readFile x15 (async) took 115ms wall time; heartbeat ticked 12 times DURING it
05

Join the discussion

Discussion (0)

Sign in to join the discussion.

No responses yet. Be the first to share what you think.

Transmission complete // awaiting log

KEEP THE
STREAK ALIVE.

Dossier 22 of 152 decoded in the Node.js track. One more won't hurt.

Back to track