Blocking the event loop
Blocking the event loop is the situation where JavaScript runs a long synchronous operation and, until it finishes, no other event is handled. The language is single threaded, so a heavy loop or a synchronous file read stops rendering, timers, promises and network callbacks alike.
Theory
TL;DR
- The event loop runs tasks one after another: callbacks, promises, timers, events.
- JavaScript is single threaded, only one instruction runs at any moment in time.
- A long synchronous operation means everything else sits in the queue and waits.
- In the browser that is a frozen UI: no reaction to clicks, scrolling or typing.
- In Node.js that is a server that does not respond, because every request is stuck behind one CPU heavy task.
- The cures: chunking, Web Workers, Worker Threads or
child_process, and asynchronous APIs instead of synchronous ones.
Quick example
console.log('Start');
for (let i = 0; i < 1e9; i++) {} // blocks the event loop
console.log('End');While that loop runs:
- the browser does not react to clicks, scrolling or typing;
- timers and promises do not run;
- the UI hangs.
What the event loop is
The event loop is the mechanism that:
- runs tasks in order (callbacks, promises, timers, events);
- handles asynchronous operations;
- is responsible for how the interface reacts and how responsive the application feels.
JavaScript is a single threaded language: only one instruction runs at any moment in time. If something takes a long time, everything else sits in the queue and waits.
Why this is bad
1. A frozen interface
The user cannot interact with the site: buttons, inputs, animations, everything is frozen.
2. Asynchronous operations do not run
Neither setTimeout, nor fetch, nor Promise.then will fire until the blocking finishes.
setTimeout(() => console.log('1s elapsed'), 1000);
const end = Date.now() + 5000;
while (Date.now() < end) {} // blocks for 5 secondsResult:
(after 5 seconds) 1s elapsedThe timer fired late: its callback was queued on time, but the queue was not being processed.
3. Lost throughput in Node.js
If a Node.js server runs a CPU heavy task (parsing a large JSON payload, encryption and so on), the remaining requests queue up and the server stops responding.
How to avoid blocking
-
Split the computation into chunks:
javascriptfunction heavyTask() { let i = 0; function step() { while (i < 1e9 && i % 1e5 !== 0) i++; if (i < 1e9) setTimeout(step); // hand control back to the event loop } step(); } -
Use Web Workers in the browser. For heavy computation run the code in a separate thread so it does not disturb the main one.
-
In Node.js use Worker Threads or
child_process:javascriptimport { Worker } from 'worker_threads'; new Worker('./heavy-task.js'); -
Do not use synchronous I/O methods:
fs.readFileSync, bad;fs.readFile, good;crypto.pbkdf2Sync, bad;crypto.pbkdf2, good.
In short
| Reason | What happens |
|---|---|
| JavaScript is single threaded | Everything runs in one thread |
| Blocking code | Delays the event loop |
| The UI stops reacting | The interface freezes |
| The server hangs | Requests are not processed |
| The fix | Asynchrony, chunking, workers |
Common mistakes
- Believing
async/awaitmakes code non blocking.awaitonly yields while waiting; a heavy synchronous computation inside anasyncfunction blocks the thread just the same. - Synchronous APIs on the server.
fs.readFileSync,crypto.pbkdf2SyncorJSON.parseover tens of megabytes inside a request handler stop the whole process, not just that one request. - Trusting
setTimeoutto be precise. A timer guarantees "no sooner than", not "exactly after": if the event loop is busy, the callback waits. - Chunking with
Promise.resolve().then(). That is a microtask, it runs in the same tick and never lets the browser paint a frame. You need a macrotask:setTimeout,MessageChannelorrequestIdleCallback. - Sending huge objects to a Web Worker without
Transferable. Structured cloning of a large buffer blocks the thread by itself; for anArrayBuffertransfer ownership instead. - Optimising blindly. Profile first (the Performance tab, or
--cpu-profin Node.js), and only then rewrite.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.