Mind~G
NodeJs

Event Loop

Introduction

Event loop allow NodeJS to perfrom Non-blocking I/O Operation like data fetching, cpu intensive tasks.

Event Loop Working

Example Code

console.log("Start")
 
setTimeout(() => {
  console.log("Timer done")
}, 2000)
 
fs.readFile("data.txt", () => {
  console.log("File reading done")
})
 
console.log("End")

Full Flow Inside NodeJS

┌────────────────────────────────────────────────────────────────────────┐
│                           YOUR JAVASCRIPT CODE                         │
│────────────────────────────────────────────────────────────────────────│
│ console.log("Start")                                                   │
│ setTimeout(() => {...}, 2000)                                          │
│ fs.readFile("data.txt", () => {...})                                   │
│ console.log("End")                                                     │
└────────────────────────────────────────────────────────────────────────┘


        ┌────────────────────────┐
        │       V8 ENGINE         │
        │ (Executes JS directly)  │
        └───────────┬─────────────┘


 ┌─────────────────────────────────────────────────────────────────────────┐
 │                     WHAT V8 HANDLES IMMEDIATELY                        │
 │  - console.log("Start") → runs instantly                               │
 │  - setTimeout() → registered, sent to LIBUV timers system              │
 │  - fs.readFile() → sent to LIBUV thread pool                           │
 │  - console.log("End") → runs instantly                                 │
 └─────────────────────────────────────────────────────────────────────────┘


          ┌──────────────────────────────┐
          │          LIBUV CORE          │
          │ Handles async work using:    │
          │   - Event Loop               │
          │   - Thread Pool              │
          └───────────┬──────────────────┘

      ┌───────────────┼──────────────────────────────┐
      ▼                                               ▼
┌───────────────────────────┐           ┌───────────────────────────┐
│        EVENT LOOP          │           │        THREAD POOL        │
│ (Controls flow and timing) │           │  (Handles heavy tasks)    │
└───────┬───────────────────┘           └───────────────┬───────────┘
        │                                               │
        ▼                                               ▼
┌─────────────────────┐                       ┌────────────────────────┐
│   TIMERS QUEUE      │                       │  WORKER THREADS        │
│(for setTimeout etc) │                       │ do fs.readFile etc.    │
└────────┬────────────┘                       └──────────┬─────────────┘
         │                                               │
         ▼                                               ▼
┌────────────────────────────┐              ┌──────────────────────────┐
│  CALLBACK QUEUE (ready)    │ <────────────┤  Task finished (file I/O)│
│ setTimeout callback placed │              │ gives result to callback │
└──────────────┬─────────────┘              └──────────────┬───────────┘
               │                                             │
               ▼                                             ▼
        ┌────────────────────────────────────────────────────────┐
        │              EVENT LOOP DECISION MAKER                 │
        │ If Call Stack empty → take next callback from queue    │
        └──────────────┬─────────────────────────────────────────┘


             ┌────────────────────┐
             │   CALL STACK (V8)  │
             │ Runs callback code │
             └─────────┬──────────┘


             ┌──────────────────────────────┐
             │       OUTPUT (Console)       │
             │  "Start"                     │
             │  "End"                       │
             │  "Timer done"                │
             │  "File reading done"         │
             └──────────────────────────────┘

Call Stack(V8 ENGINE): where current code runs.

Callback Queue: where async callbacks wait until the stack is empty.

Step-by-Step Flow Explanation

Step 1 – V8 starts executing

  1. console.log("Start") → runs immediately → printed to console

  2. setTimeout(..., 2000) → registered with Libuv timer system → not blocking

  3. fs.readFile("data.txt", callback) → passed to Libuv Thread Pool to read file in background

  4. console.log("End") → runs immediately → printed to console At this moment output is:

Start
End

Step 2 – Libuv starts working

  • Libuv has two main parts:
    1. Timers System(Event Loop) → for setTimeout and setInterval
    2. Thread Pool → for slow operations (like file I/O, DNS lookups etc) setTimeout waits for 2 seconds fs.readFile starts reading the file in the background

The event loop continues checking: “Is any task finished?”

Step 3 – Background tasks finish

  • After 2 seconds:

Timer system says “Timer done” and pushes its callback to the Callback Queue

  • When file reading finishes:

The thread pool sends the “File reading done” callback to the Callback Queue

Step 4 – Event Loop picks callbacks

The Event Loop checks the Call Stack If it is empty, it picks the next callback from the queue and executes it

So it will run:

  1. Timer callback → prints “Timer done”

  2. File read callback → prints “File reading done”

Now final output is:

Start
End
Timer done
File reading done

Interview Questions


1. What is the Event Loop in NodeJS?

Event Loop is the part of NodeJS that controls how your code runs.
It allows NodeJS to do many tasks without waiting (non-blocking).
It checks if the call stack is empty and then runs callbacks from queues.


2. Is NodeJS single-threaded?

Yes. NodeJS runs JavaScript on one main thread,
but it uses background threads (libuv thread pool) for slow tasks like file I/O.


3. What is the difference between microtask and macrotask?

  • Microtasks: run just after the current code, before timers.
    Example: Promise, process.nextTick.
  • Macrotasks: run in later phases of event loop.
    Example: setTimeout, setImmediate, I/O callbacks.

4. What is the order of execution between Promise and setTimeout?

Promise callback runs before setTimeout.
Because Promises are microtasks and setTimeout is a macrotask.


5. What is process.nextTick()?

It is like a microtask.
It runs immediately after current function, before any Promise or timer.


6. What is the difference between setTimeout and setImmediate?

Both run after current code, but:

  • setTimeout(fn, 0) runs in timers phase
  • setImmediate(fn) runs in check phase
    Their order is not guaranteed if both are called in the main script.

7. What are phases of Event Loop in NodeJS?

  1. Timers Phase → runs setTimeout and setInterval
  2. Pending Callbacks Phase → runs some system callbacks
  3. Idle / Prepare Phase → internal use
  4. Poll Phase → gets new I/O events
  5. Check Phase → runs setImmediate
  6. Close Callbacks Phase → runs close events like socket close

8. What happens when you call fs.readFile()?

It goes to libuv thread pool, not the main thread.
When file reading is done, its callback is added to the event loop queue.


9. What runs first — Promise or process.nextTick()?

process.nextTick() runs before Promises.


10. What is libuv?

Libuv is a C library used by NodeJS for:

  • Managing the event loop
  • Handling thread pool for async I/O operations

11. What is non-blocking I/O?

Non-blocking means NodeJS does not wait for a task to finish.
It starts the task, then continues running other code.


On this page