Course contentsShow
← Node.js
Lesson 239 of 1,9803. Asynchronous Patterns and Flow ControlFree lesson

Preventing Event Loop Starvation

You will refactor heavy computational tasks into event-driven chunks that allow the event loop to breathe.

Preventing Event Loop Starvation

In this lesson, you will learn how to break down heavy, CPU-intensive tasks into smaller, time-sliced chunks to keep your Node.js application responsive.

The Problem: Blocking the Loop

Node.js runs on a single main thread—the "Event Loop." Think of this loop as a busy waiter in a restaurant. If the waiter gets stuck performing a single, long calculation (like processing a massive array of data), they cannot take new orders, deliver food, or talk to other customers. While the waiter is stuck, the entire restaurant feels "frozen." This is called Event Loop Starvation.

The Solution: Time-Slicing

To prevent this, we "slice" our heavy work into smaller pieces. Instead of doing all the work at once, we do a little bit, then tell the Event Loop, "Hey, you're free to handle other tasks for a moment." We can then use setImmediate or setTimeout to schedule the next chunk of our work.

Consider this inefficient, blocking approach:

function heavyProcess(items) {
  for (const item of items) {
    // Imagine this loop runs for millions of records
    // This will starve the event loop!
    performComplexCalculation(item);
  }
}

By refactoring this into an async pattern, we allow the loop to breathe:

function processChunk(items, index = 0) {
  const chunkSize = 100;
  const end = Math.min(index + chunkSize, items.length);

  for (let i = index; i < end; i++) {
    performComplexCalculation(items[i]);
  }

  if (end < items.length) {
    // Yield control back to the event loop before continuing
    setImmediate(() => processChunk(items, end));
  }
}

In this version, we process 100 items, and then use setImmediate to queue the next batch. This allows the Event Loop to process pending I/O, handle incoming requests, or fire timers in between our chunks, ensuring your application remains snappy even under a heavy computational load.

Key Takeaway: Never execute long-running synchronous loops; break them into smaller tasks and yield control back to the Event Loop to keep your application responsive.