Skip to main content

Command Palette

Search for a command to run...

Node.js Event Loop Explained

Updated
6 min readView as Markdown

So there is one of the interesting questions which came in my mind while learning backend and that was, how does Node.js able to handle so many things at once if it is single-threaded ? Like, how does it not just...freeze while running the Code ?

and I got the answer and that is the Event loop. And once I actually understood it, there are lot of new things about Node that are clicked for me. Let me explain it, the way it finally started making sense to me.

The Single Thread Problem

JavaScript runs on a single thread which means that it can only do one thing at a time. One line start to executes, then it goes to next, then next one.

Now you imagine that you're building a server. Someone sends a request, your server goes and fetches data from a database - and while that's all happening, another request comes in, now think about it that what does Node will do?

Node will wait ?

or

Block everything ?

If that's how it worked, Node would become a terrible run-time environment for servers. if we get a one slow database query then it would freeze our entire application but that's not what happens with it and that's where the event loop comes in picture.

What is the Event Loop ?

Event loop is basically we can say it behave like Node's task manager.

Its whole job is to keep checking - "is there some code that is ready to run? if its ready, then run it. is there something else which ready now too ? then run that too"

It doesn't do the heavy lifting itself on its own. It just coordinates that what runs and when will it run.

just think of it like a restaurant manager. The chef is your CPU and you can only cook one dish at a time. But manager who is event manager keeps track of all the orders, knows which ones are ready to be picked up, and makes sure nothing just sits there to be forgotten.

Call Stack

Before you are going to understanding the event loop, you reallly need to know about the call stack.

The call stack is where your code is going to runs in a queue. When you simply calls a function, it goes on the stack. When it finishes that, it comes off. this process took place simply.

function greet() {
  console.log("Hello");
}

greet();

greet function goes on the stack then it runs or then it comes off and it's done.

The problem is that if there is something which slow down like a file read or a network request sits on stack, everything which is behind it is gone to be stuck and waiting. The stack is totally blocked now. Node solves this by not just putting slow operations on the stack directly.

Task Queue

When Node encounters an async operation in code like code of reading a file, or making an API call, or a setTimeout - it hands that work to be off. Not to the call stack, but to system under the hood which is libuv, a C library - but you don't need to know that right now we will cover this later on.

That system started to work in the background. Mean while, theNode keeps running other code. When the background work finishes, it doesn't just jump back into your code. It puts a callback as the function you passed to handle the resultant into the task's queue.

The event loop watches two things now:

Is the call stack is empty or not ?

Is there anything which is waiting in the task queue ?

If we founf that the stack is empty and there's something which is in the queue - it can picks it up and pushes it on to the stack that gets to run.

That's the whole loop hope that you get this in a better way now.

How Async Actually Works

console.log("start");

setTimeout(() => {
  console.log("timeout done");
}, 2000);

console.log("end");

Output:

start
end
timeout done

Here's what happened:

  • "start" runs immediately as it's on the stack

  • setTimeout is encountered — Node hands it off now, and start to keeps going

  • "end" runs after start as settimeout needs a delay

  • and now the Stack is empty which mean

  • 2 seconds later, the timer's callback will be in the task queue

  • Event loop will picks it up, pushes it to the stack

  • and now the "timeout done" runs

Notice Node that didn't sit and wait for 2 seconds. It start to moved on and again came back with it.

Timers vs I/O Callbacks

There are different types of async callbacks, and they all don't wait in the same queue but at a high level, you can think of two categories:

Timers : stuff like setTimeout and setInterval. These wait for a specific time before their callback are become eligible to run.

I/O callbacks : these things are like file reads, network requests, database queries. These will wait until operation is going to be done not by a fixed time, then their callback is queued back up again.

The event loop handles both. It checks timers, it checks I/O, it keeps the flow going. You don't have to think about the order too much at this stage just know that Node isn't ignoring them, it's managing them.

Why This Makes Node Scalable

Traditional servers are like a basic multithreaded server which can handle each request by directly by spinning up a new thread. that's how it works but threads eat memory and there's a limit to how many you can have.

Node takes a different approach from others One thread, Non-blocking. While one request is waiting on a database, another request is already started to being handled this is the whole concept of Node.

This is why Node works so well for these things like which are:

  • APIs that are to be hit a database

  • they can be Real-time chat apps

  • Anything with lots of simultaneous connections

It's all is not just because of Node is faster at processing things. it's just because of it's extremely good at not blocking while waiting for some code to run.