Interview frequency: …
Short answer
It happens when a long synchronous computation monopolizes the main thread, preventing I/O and timers from being processed, and it can be avoided by chunking the computation or delegating it to worker threads.
Explanation
Since the event loop is single-threaded, any long loop leaves the server unable to receive new HTTP requests or send responses. The solution is either to break up the task using setImmediate to return control to the loop periodically, or to isolate the computations in independent worker threads.
Code example
// Blocks the event loop: no I/O or timers can run until this returns
function sumSquares(n) {
let sum = 0;
for (let i = 0; i < n; i++) sum += i * i;
return sum;
}
// Chunked: yields to the event loop between slices with setImmediate
function sumSquaresChunked(n, chunk = 1e6) {
return new Promise((resolve) => {
let i = 0, sum = 0;
(function slice() {
const end = Math.min(i + chunk, n);
for (; i < end; i++) sum += i * i;
i < n ? setImmediate(slice) : resolve(sum);
})();
});
}
// For genuinely heavy work, move it to a thread:
// import { Worker } from "node:worker_threads";
// new Worker("./sum-worker.js", { workerData: n });Common mistakes
- Relying on process.nextTick to break up tasks, as the queue still monopolizes the thread and prevents I/O events from being processed.