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
setIntervalheartbeat 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.