Node.js: Code Outside the Browser / Async Programming in Node.js

Blocking and Non-Blocking: Asynchronous Nature of Node.js

⚡ Why This Topic Matters

Grasping the difference between synchronous, asynchronous, blocking, and non-blocking code is core to understanding Node.js — and it underpins everything else in this course.


🔒 Synchronous (Blocking) Code

📖 What It Means

  • Code is executed line by line, one statement after another.

  • Each line waits for the previous line to finish before running.

💻 Example

const fs = require('fs');
const textIn = fs.readFileSync('./txt/input.txt', 'utf8');
console.log(textIn);

Here:

  1. First, the fs module is loaded.

  2. Then, the file is read.

  3. Only after that finishes, the result is logged.

⚠️ The Problem

  • This is called blocking code because a slow operation (like reading a large file) blocks everything else from running until it completes.

  • This becomes a serious issue in Node.js due to how Node is designed (explained below).


🚀 Asynchronous (Non-Blocking) Code

📖 What It Means

  • Slow or heavy tasks get offloaded to run in the background.

  • Rather than waiting around, the rest of the code continues executing right away.

  • Once the background task wraps up, a pre-registered callback function fires to handle the result.

💻 Example

console.log('Will read file!');

fs.readFile('./txt/input.txt','utf8',(err, data)=>{
 console.log(data);
});

console.log('Reading file...');
  • readFile kicks off reading the file in the background.

  • The program doesn't pause — it moves straight to the next line.

  • That's why "Reading file..." logs before the file's contents — reading takes time.

  • Once the file finishes loading, the callback runs and logs the actual data.

✅ This is what makes it non-blocking — nothing else in the program freezes while the read happens.


🧵 Why Does Node.js Need This? The Single-Thread Explanation

🔑 Key Concept: Node.js Runs on a Single Thread

  • A thread is the path of instructions the CPU runs — it's where your code executes.

  • A Node.js app runs on just one thread, no matter how many users it has — 5 or 5 million, everyone shares it.

⚠️ The Problem: Blocking Code on a Single Thread

  • If one user triggers blocking code — say, a file read that takes a second — everyone else has to wait that same second before the thread is free again.

  • Even simple actions like logging in get stuck in line.

  • With a few users, you won't notice. At scale, it becomes a real bottleneck.

Note: This is simplified — we'll cover Node's internals more deeply later.

✅ The Fix: Asynchronous Code

  • Async file reading moves the heavy work off the main thread.

  • The main thread stays free to handle other requests.

  • Once the background task finishes, its callback runs to process the result.

  • End result: every user gets served efficiently, with no single slow task holding up the rest.

🔄 What "I/O" Means

  • I/O = Input/Output — operations like:

    • 📂 Reading/writing files

    • 🌐 Handling network requests

  • Node.js's entire design (built around callbacks) exists specifically to support non-blocking I/O, making it fast and scalable.

⚖️ Comparison with Other Languages

  • Languages like PHP use a different model — a new thread is created for each user.

  • Node.js's creator chose the single-thread + non-blocking callback model instead, believing it's better suited for building highly performant, scalable web applications.


💡 Important Clarification About Callbacks

  • Passing a function into another function (a "callback") is common in JavaScript — but this does NOT automatically make code asynchronous.

  • Only certain built-in Node API functions (like readFile) are specifically designed to behave asynchronously.

  • Many more such functions will be explored throughout the course.