Skip to main content

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, nor Promise.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

javascript
function infinite() { while (true) { console.log('forever...'); } } infinite();

What happens step by step

  1. The function infinite() is pushed onto the call stack.
  2. The while (true) loop starts and never finishes.
  3. 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

javascript
setTimeout(() => console.log('I will not run'), 0); while (true) {} // infinite loop

Explanation:

  • setTimeout puts 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

ConsequenceDescription
Stack is blockedThe code never leaves the function, so the stack is not released
Event loop stopsTask queues (timers, promises) are not processed
Page freezesThe UI is not repainted, the browser may show "Page is not responding"
No reaction to eventsClicks, scrolling and typing do not work

How to avoid blocking

Use asynchrony, or split the task into chunks.

Option 1: setTimeout

javascript
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:

javascript
function animate() { // draw a frame requestAnimationFrame(animate); } animate();

Option 3: a Web Worker, when you need heavy computation. Move it to a separate thread:

javascript
// worker.js onmessage = e => { while (true) {} // can run long, the UI stays responsive };

Summary

TermExplanation
Infinite loop in a functionNever leaves the call stack
ConsequenceThe event loop is blocked, the browser freezes
SolutionSplit 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 async function and calling that asynchrony. An async function without an await on 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 exceeded instead.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.