How the Event Loop Works
In the last chapter we said Node.js does one thing at a time but never waits around. This chapter shows how that trick works. The answer is a piece of machinery called the event loop — a repeating cycle that checks whether anything needs attention and runs it.
The restaurant analogy
Imagine a cook with one stove. Orders arrive on a counter. The cook picks up an order, starts it, and — if the dish needs time in the oven — does not stand and stare at the oven. Instead, the cook starts the next order. When the oven dings, the cook finishes that dish.
Node.js is the cook. The oven is the outside world: the disk, the network, timers. The counter is a list of pending tasks, and the ding is an event: a signal that something finished. The event loop is the cook's habit of constantly returning to the counter to see what's next.
A picture of the loop
Show diagram source
flowchart TD
A[Run your JavaScript code] --> B{Is anything finished?}
B -- Yes --> C[Run the callbacks for finished work]
C --> B
B -- No --> D[Sleep until something finishes]
D --> BA callback is just a function you hand to Node.js saying "call me back when this is done." The loop keeps circling forever — for a web server, literally for months.
Seeing it happen
This script starts a timer for two seconds, then does a slow, pointless calculation (counting a lot), then logs when it's done:
// slow.js — run with: node slow.js
setTimeout(() => {
console.log('timer fired after 2 seconds');
}, 2000);
let total = 0;
for (let i = 0; i < 5_000_000_000; i++) {
total++;
}
console.log('finished counting');You will see "finished counting" before "timer fired," even though the timer was set first. The counting is a tight loop of plain JavaScript — it never talks to the outside world, so it never pauses, and the event loop cannot step in until it's done.
Contrast that with file reading from the previous chapter. Reading a file goes to the operating system, so the loop is free to run other code and only runs your callback when the file actually arrives. Waiting for the outside world is cheap; waiting inside your own code is not.
What the loop does not do
The event loop is not multiple threads running your JavaScript. At any instant, exactly one piece of your code is executing. That is a feature: two functions can never interfere with the same variable at the same moment, a whole class of bugs that plague other languages simply cannot happen. For genuinely heavy computation, Node offers ways to hand work to separate workers — a topic beyond this tutorial, but worth knowing exists.
The habit to build
Write code that starts a slow task, says what to do when it finishes, and returns quickly. Almost every Node.js API you will meet — files, network, timers — is shaped for this: you hand it a callback (or receive a promise, which we cover soon) and move on.
Exercise
A function in your server loops for five seconds doing pure arithmetic with no file or network access. What happens to other requests during that time?
Show answer
They all wait. The event loop cannot run anything else while that blocking JavaScript is executing, because Node runs one piece of code at a time. Move heavy computation out of the request path or split it up.
Exercise
Why did the timer in slow.js fire after the counting finished, even though it was set for two seconds?
Show answer
The loop only checks for finished work between pieces of JavaScript code. Counting never paused, so the loop couldn't run the timer callback until counting ended.
Spotted a mistake, or code that does not work?