Blocking and non-blocking code
What blocking and non-blocking code is
| Term | What it means |
|---|---|
| Blocking code | Program execution stops until the operation finishes |
| Non-blocking code | The program keeps running, without waiting for the operation to finish |
1. Blocking code
The program waits for an operation (for example, reading a file or querying a database) to finish before moving on.
Example (synchronous file read in Node.js):
const fs = require('fs');
console.log('1. Start');
const data = fs.readFileSync('file.txt', 'utf8'); // a blocking call
console.log('2. File read');
console.log('3. End');Output:
1. Start
2. File read
3. EndWhile fs.readFileSync reads the file, the whole thread is blocked, Node.js can't handle any other requests or events.
2. Non-blocking code
The program doesn't wait, it starts the operation and immediately moves on. Once the operation finishes, the result comes back through a callback, Promise, or async/await.
Example (asynchronous file read):
const fs = require('fs');
console.log('1. Start');
fs.readFile('file.txt', 'utf8', (err, data) => {
console.log('2. File read');
});
console.log('3. End');Output:
1. Start
3. End
2. File readHere fs.readFile runs in the background (through libuv),
while the main thread isn't blocked and keeps working.
Once the file is ready, the callback lands in the event queue (the event loop).
3. What makes code blocking
Any operation that waits for I/O to finish on the main thread is blocking:
fs.readFileSync(),fs.writeFileSync()JSON.parse()on huge data- heavy computation (for example, a loop over millions of iterations)
- synchronous network requests (if Node.js had them)
The problem:
In single-threaded Node.js, one blocking section of code can freeze the entire server.
4. How Node.js makes code non-blocking
Node.js implements a non-blocking I/O model using:
- the event loop,
- libuv (the library that creates the background thread pool).
The principle:
- JS code starts an operation (for example, reading a file).
- It's handed to libuv → it runs on another thread.
- The main thread keeps running.
- Once the operation finishes → the callback/Promise goes back to the event loop.
An analogy
Picture a coffee shop:
| Scenario | What happens |
|---|---|
| Blocking | The barista takes an order, waits for the coffee to brew, and only then takes the next order. |
| Non-blocking | The barista takes an order, hands it off to be made, and immediately takes the next one. Once the coffee is ready, they just hand it over. |
Result: more customers served, nobody waits for nothing.
5. A practical example: a web server
A blocking server
const http = require('http');
const fs = require('fs');
http.createServer((req, res) => {
const data = fs.readFileSync('data.json'); // blocks the thread!
res.end(data);
}).listen(3000);One request "hangs", everyone else waits.
A non-blocking server
const http = require('http');
const fs = require('fs');
http.createServer((req, res) => {
fs.readFile('data.json', (err, data) => {
res.end(data);
});
}).listen(3000);The server handles many requests at once, because file reads run in the background.
6. Comparison table
| Criterion | Blocking code | Non-blocking code |
|---|---|---|
| Execution model | Synchronous | Asynchronous |
| Execution thread | One, and it waits | One, but it doesn't wait |
| Performance | Slow under I/O | High under I/O |
| Good for | Simple scripts | Servers, APIs |
| Example in Node.js | fs.readFileSync() | fs.readFile() |
Summary
- Blocking code halts the program until the operation finishes.
- Non-blocking code lets other tasks run while the operation runs in the background.
- Node.js is built around non-blocking I/O and the event loop, which is why it can handle thousands of requests on a single thread.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.