Infinite loop
If a function contains an infinite loop, JavaScript will never release the call stack and the event loop will stop: no other task, neither timers, nor promises, nor clicks, nor interface repaints, will be able to run. To the user this looks like a page that has completely frozen.
Theory
TL;DR
- An infinite loop keeps the function from returning, so it stays in the call stack forever.
- While the stack is busy, the event loop cannot take a new task from the queue.
- Neither
setTimeout, norPromise.then, nor event handlers will fire. - The browser stops repainting the UI and eventually offers to close the tab.
- The fix: split work into chunks (
setTimeout,requestAnimationFrame) or move computation into a Web Worker.
Quick example
function infinite() {
while (true) {
console.log('forever...');
}
}
infinite();What happens step by step
- The function
infinite()is pushed onto the call stack. - The
while (true)loop starts and never finishes. - The engine never leaves the function, which means:
- the stack is never released,
- the event loop cannot take the next task,
- the browser stops responding to clicks and scrolling, and sometimes even DevTools freezes.
Why this happens
JavaScript is a single threaded language. At any moment it can execute only one piece of code, the one currently in the call stack.
Until the function returns, the engine will not switch to other tasks: not to setTimeout, not to Promise.then. The task queue simply piles up and waits for a free stack that will never come.
A timer that never fires
setTimeout(() => console.log('I will not run'), 0);
while (true) {} // infinite loopExplanation:
setTimeoutputs the callback into the macrotask queue;- while
while (true)runs, the stack is not released; - the event loop cannot pull the task out of the queue;
console.log('I will not run')never executes.
Consequences
| Consequence | Description |
|---|---|
| Stack is blocked | The code never leaves the function, so the stack is not released |
| Event loop stops | Task queues (timers, promises) are not processed |
| Page freezes | The UI is not repainted, the browser may show "Page is not responding" |
| No reaction to events | Clicks, scrolling and typing do not work |
How to avoid blocking
Use asynchrony, or split the task into chunks.
Option 1: setTimeout
function loop() {
console.log('iteration');
setTimeout(loop, 0); // lets the engine breathe between iterations
}
loop();Option 2: requestAnimationFrame, a good fit for visual work and animations:
function animate() {
// draw a frame
requestAnimationFrame(animate);
}
animate();Option 3: a Web Worker, when you need heavy computation. Move it to a separate thread:
// worker.js
onmessage = e => {
while (true) {} // can run long, the UI stays responsive
};Summary
| Term | Explanation |
|---|---|
| Infinite loop in a function | Never leaves the call stack |
| Consequence | The event loop is blocked, the browser freezes |
| Solution | Split work into chunks (setTimeout, requestAnimationFrame, Web Workers) |
Common mistakes
- Thinking that
setTimeout(fn, 0)will "interrupt" the loop. The callback only joins the queue and runs after the stack is free. - Assuming promises have priority over blocking code. Microtasks also wait for a free stack.
- Moving a heavy loop into an
asyncfunction and calling that asynchrony. Anasyncfunction without anawaiton a real asynchronous operation runs synchronously and blocks the thread just the same. - Writing an exit condition that never becomes false, for example forgetting to increment the counter or mutating a copy instead of the variable itself.
- Using infinite recursion instead of a loop and expecting a freeze: there you get a fast
RangeError: Maximum call stack size exceededinstead.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.