At its heart, the JavaScript engine is synchronous and single-threaded.
This means JavaScript, by itself, is linear. It executes code line-by-line. If the stack is occupied, nothing else can run.
Blocking occurs when a heavy computation is performed in the Call Stack. While the Stack is busy, the application is paralyzed.
function heavyTask() {
const end = Date.now() + 5000;
while (Date.now() < end) {
/* CPU is trapped here for 5s */
}
}
heavyTask();
console.log("This waits 5 seconds to run");JavaScript handles slow tasks by outsourcing them to the Host Environment (the Browser or Node.js). The Runtime is a collaboration between three distinct pillars:
These are threads provided by the browser (Web APIs) or Node.js (C++ APIs). They handle the waiting in the background without blocking the Call Stack.
fetch or XHR requests.setTimeout and setInterval.The environment doesn't push code back to the stack directly. It places callbacks into one of two specialized queues.
Promise callbacks (.then, .catch), queueMicrotask, MutationObserver.setTimeout, setInterval, setImmediate, I/O, UI Rendering.The Event Loop is a continuously running process that handles execution of callback. Follows the following order :
| Component | Responsibility | Threading | Priority |
|---|---|---|---|
| Call Stack | Executes JS logic | Single Thread | Immediate |
| Environment APIs | Background waiting | Multi-threaded | N/A |
| Microtask Queue | Promises | Passive Queue | High (Run All) |
| Macrotask Queue | Timers / Events | Passive Queue | Low (Run One) |
| Event Loop | Orchestration | Continuous Loop | Monitor |
Answer: No. Even with 0ms, the callback is placed in the Macrotask Queue. The Event Loop must first finish the current script, then flush the entire Microtask Queue, and then handle rendering before it finally picks up your setTimeout callback.