Event Loop Starvation

Hard

Event loop starvation occurs when one type of task blocks others from running. Infinite microtasks can starve macrotasks. Long-running synchronous code blocks everything. Understanding these scenarios helps prevent UI freezing and ensures responsive applications.

Interactive Visualization

Call Stack

LIFO - Last In, First Out

Stack empty

Key Points

  • Infinite microtasks prevent macrotasks from running
  • Long sync operations block the entire thread
  • Use setTimeout(fn, 0) to yield control
  • Break heavy work into chunks
  • Use Web Workers for CPU-intensive tasks

Code Examples

Microtask Starvation

// This blocks forever!
function recursivePromise() {
  Promise.resolve().then(() => {
    console.log("Microtask");
    recursivePromise();
  });
}

// recursivePromise();
// setTimeout(() => console.log("Never!"), 0);

// The microtask queue never drains
// setTimeout never gets a chance

Recursively queueing microtasks prevents macrotasks from ever executing.

Yielding with setTimeout

// Bad: Blocks for 5 seconds
function heavyTask() {
  for (let i = 0; i < 1000000000; i++) {} // Blocks!
}

// Better: Break into chunks
function chunkedTask(i = 0) {
  if (i >= 1000000000) return;
  
  // Do chunk of work
  for (let j = 0; j < 1000; j++, i++) {}
  
  // Yield to event loop
  setTimeout(() => chunkedTask(i), 0);
}

// Now other code can run between chunks

Use setTimeout to yield control between chunks of work.

Common Mistakes

  • Running heavy computation on main thread
  • Creating infinite microtask loops
  • Not yielding control in long operations

Interview Tips

  • Know how to identify starvation scenarios
  • Know solutions: setTimeout yielding, Web Workers
  • Understand the recursive Promise problem