Non-blocking code
Non-blocking code is code that does not stop the thread from executing; it delegates long operations (I/O, network, timers, files) and carries on with other tasks. Its opposite, blocking code, does not release the main thread until it finishes.
Theory
TL;DR
- Blocking code holds the main thread: while it runs there is no click handling, no repainting and no next function.
- Non-blocking code hands the long operation outside and moves on immediately, receiving the result later through a callback or a promise.
- This matters because JavaScript is single-threaded: if one piece of code hangs, the rest waits.
- The machinery: asynchronous APIs (
setTimeout,fetch,async/await), external Web APIs or the libuv thread pool, plus the event loop that returns the result. - Typical non-blocking operations: timers, network, files in Node.js, database queries, event listeners, promises.
- Non-blocking is not the same as parallel: the engine runs one callback at a time, it just does not idle while waiting.
Quick example
console.log('start');
setTimeout(() => {
console.log('one second passed');
}, 1000);
console.log('end');
// start
// end
// one second passedThe thread was never blocked: JS freely handled other events while the timer «worked in the background».
What blocking code is
Blocking code does not release the main thread until it finishes. While the operation runs, JavaScript cannot do anything else.
// Simulating a long calculation
function heavyCalculation() {
const start = Date.now();
while (Date.now() - start < 3000) {} // wait 3 seconds
console.log('calculation finished');
}
console.log('start');
heavyCalculation();
console.log('end');Result:
start
(frozen for 3 seconds)
calculation finished
endEverything stopped for 3 seconds: the interface «froze», the server stopped answering. That is blocking code.
What non-blocking code is
The non-blocking version of the same delay:
console.log('start');
setTimeout(() => {
console.log('one second passed');
}, 1000);
console.log('end');What happens:
- JS calls
setTimeoutand hands the task to the browser (Web API). - Execution continues,
'end'is printed right away. - After 1 second the callback returns to the task queue and runs.
Result:
start
end
one second passedWhy this matters in JavaScript
JavaScript is single-threaded, which means:
- at any moment only one piece of code is executing;
- if one piece hangs, the rest wait.
To avoid freezes, JS uses:
- asynchrony (
setTimeout,fetch,async/await); - external APIs (Web APIs or the libuv thread pool);
- the event loop, to return the result once it is ready.
Examples of non-blocking operations:
| Operation type | Example | What it does |
|---|---|---|
| Timers | setTimeout, setInterval | run later |
| Network | fetch, XMLHttpRequest | wait for the server response in the background |
| Files (Node.js) | fs.readFile | read the disk asynchronously |
| Database queries | db.query | wait for the result without blocking |
| Event listeners | addEventListener('click') | fire on an event |
| Promises | Promise, async/await | defer execution until the operation completes |
The difference shown in Node.js
The blocking version:
const fs = require('fs');
console.log('reading the file...');
const data = fs.readFileSync('large.txt', 'utf8'); // blocks the thread
console.log('file read:', data.length);While the file is being read, the server serves no other requests.
The non-blocking version:
const fs = require('fs');
console.log('reading the file...');
fs.readFile('large.txt', 'utf8', (err, data) => {
console.log('file read:', data.length);
});
console.log('other code keeps running...');Node.js hands the task to the system (I/O) and keeps executing. When the file is ready, the callback comes back through the event loop.
Why «non-blocking» is not «parallel»
This is a common interview mistake. Non-blocking code does not mean everything runs in parallel. JS still runs one callback at a time, but it does not waste time waiting for I/O. During that wait the engine handles other tasks, which is what creates the impression of parallelism.
| Type | What it does | Example | Consequence |
|---|---|---|---|
| Blocking | Stops the thread until it finishes | fs.readFileSync() | The UI or the server freezes |
| Non-blocking | Delegates the task, keeps working | fs.readFile(), fetch() | High responsiveness |
Summary: non-blocking code is a way of writing programs where long operations (I/O, network, timers) run asynchronously, without getting in the way of the main logic and without «freezing» the thread. It underpins JS asynchrony (callbacks, promises, async/await), Node.js performance and smooth interfaces in the browser.
Common mistakes
- Assuming an
asyncfunction is automatically non-blocking. A heavy loop inside anasyncfunction blocks the thread just like any other. - Using the synchronous variants of APIs on the server:
fs.readFileSync,crypto.pbkdf2Syncandzlib.gzipSyncstall the handling of every request. - Confusing non-blocking with parallel and expecting two consecutive
awaitcalls to run at the same time. Real concurrency needsPromise.all. - Thinking the delay in
setTimeoutis exact. It is a minimum delay: the callback waits until the stack is empty. - Forgetting about CPU-bound work: only Web Workers, Worker Threads or native code can move it off the thread, asynchronous syntax cannot.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.