# Blocking vs Non-Blocking Code in Node.js


Node.js runs on single thread. Blocking code freezes whole server. Non-blocking code keep server alive. Difference = slow API vs fast API.

This about blocking, non-blocking, and async patterns in Node.js.

* * *

## What Blocking Code Means

Blocking = waiting. Code wait for operation finish before continue.

### Simple Definition

Blocking code pause execution until task complete. Nothing else happen. Like stuck in line at store.

### Real Analogy

Restaurant waiter without non-blocking:

```
Waiter take order from customer 1.
Wait for kitchen finish cooking.
[Stand there 10 minutes doing nothing]
[Customer 2 wait, customer 3 wait, customer 4 wait]
Finally food ready.
Waiter bring food to customer 1.
NOW waiter take order from customer 2.
```

Bad service. Customers angry. Waiter waste time.

### The Problem

```javascript
// Blocking code
const fs = require('fs');

console.log('Start reading file');
const data = fs.readFileSync('large-file.txt');  // BLOCK HERE
console.log('File read complete');
console.log(data);
```

What happen:

```
1. Server start
2. Start reading file [WAIT]
3. [WAIT] [WAIT] [WAIT]   <- Nothing happen for 5 seconds
4. File finally loaded
5. Print data
6. During step 3, if 100 users try access server, ALL wait
```

### Why Blocking Kill Servers

One user read file = 5 seconds.
10 users read file = 50 seconds wait for user 10.
100 users? Server dead.

* * *

## What Non-Blocking Code Means

Non-blocking = don't wait. Code start task, move on. When task done, callback fire.

### Simple Definition

Non-blocking code start operation and continue. Task happen background. When done, callback tell code.

### Real Analogy

Restaurant waiter WITH non-blocking:

```
Waiter take order from customer 1.
Send order to kitchen.
[Keep going - don't wait]
Waiter take order from customer 2.
Waiter take order from customer 3.
Kitchen finish customer 1 food.
Waiter bring food.
[Meanwhile take order from customer 4]
Kitchen finish customer 2 food.
Waiter bring food.
```

Good service. Customers happy. Waiter busy but move fast.

### Code Example

```javascript
// Non-blocking code
const fs = require('fs');

console.log('Start reading file');

fs.readFile('large-file.txt', (err, data) => {
  // This callback run LATER when file ready
  console.log('File read complete');
  console.log(data);
});

console.log('Request sent, moving on');
```

What happen:

```
1. Server start
2. Start reading file (DON'T WAIT)
3. Move to next line immediately
4. "Request sent, moving on" print
5. File load in background
6. When ready, callback fire
7. Print data
```

During file read, server handle other users.

* * *

## Why Blocking Slow Servers Down

### Timeline Comparison

**Blocking (synchronous):**

```
Time (seconds)
0s   ├─ User 1 come
     ├─ Read file [BLOCK]
5s   ├─ File done
     ├─ User 2 come [wait in line]
     ├─ Read file [BLOCK]
10s  ├─ File done
     ├─ User 3 come [wait in line]
     ├─ Read file [BLOCK]
15s  └─ File done

Total time for 3 users = 15 seconds
```

**Non-blocking (asynchronous):**

```
Time (seconds)
0s   ├─ User 1 come
     ├─ Start read file (don't wait)
0s   ├─ User 2 come
     ├─ Start read file (don't wait)
0s   ├─ User 3 come
     ├─ Start read file (don't wait)
5s   └─ All 3 files ready, return data to users

Total time for 3 users = 5 seconds
```

### Real Impact

With blocking:
- 100 users = 500 seconds (8+ minutes)
- Server crash or hang

With non-blocking:
- 100 users = 5 seconds
- Server smooth

### Code Proof

```javascript
// BLOCKING - slow
const fs = require('fs');
console.time('Blocking');

for (let i = 0; i < 3; i++) {
  const data = fs.readFileSync('file.txt');  // Wait each time
  console.log(`Read ${i}`);
}

console.timeEnd('Blocking');
// Blocking: 3000ms (each file take ~1 second)
```

```javascript
// NON-BLOCKING - fast
const fs = require('fs');
console.time('NonBlocking');

for (let i = 0; i < 3; i++) {
  fs.readFile('file.txt', (err, data) => {
    console.log(`Read ${i}`);
  });
}

console.timeEnd('NonBlocking');
// NonBlocking: 10ms (all start at once)
```

* * *

## Async Operations in Node.js

Node.js have many built-in async functions. Don't use Sync version in production.

### File Operations

**Blocking (bad):**

```javascript
const fs = require('fs');

const data = fs.readFileSync('users.json');  // DON'T DO THIS
console.log(data);
```

**Non-blocking (good):**

```javascript
const fs = require('fs');

fs.readFile('users.json', (err, data) => {
  if (err) {
    console.error('File error:', err);
    return;
  }
  console.log(data);
});
```

### Database Calls

**Blocking (bad):**

```javascript
// Fake sync DB call (most real DB have this)
const user = db.getUserSync(1);  // Block waiting for DB
console.log(user);
```

**Non-blocking (good):**

```javascript
// Real async DB call
db.getUser(1, (err, user) => {
  if (err) {
    console.error('DB error:', err);
    return;
  }
  console.log(user);
});
```

### Network Requests

**Blocking (impossible, no sync version):**

```javascript
// This don't exist - network always async
const response = http.requestSync(url);  // Doesn't exist
```

**Non-blocking (only way):**

```javascript
const http = require('http');

http.get(url, (res) => {
  let data = '';
  res.on('data', (chunk) => {
    data += chunk;
  });
  res.on('end', () => {
    console.log(data);
  });
});
```

* * *

## Callbacks: Simple Non-Blocking Pattern

Callback = function that run later.

### What is Callback?

Callback = tell Node.js "When done, run this function".

```javascript
fs.readFile('file.txt', (err, data) => {
  // This function run LATER when file ready
  console.log(data);
});
```

Function `(err, data) => { ... }` = callback.

### Callback Pattern

```javascript
function readUserFile(callback) {
  fs.readFile('user.json', (err, data) => {
    if (err) {
      callback(err);  // Pass error to callback
      return;
    }
    callback(null, data);  // Pass data to callback
  });
}

// Use it
readUserFile((err, data) => {
  if (err) {
    console.error('Error:', err);
  } else {
    console.log('User:', data);
  }
});
```

### Callback Hell (Problem)

Nested callbacks get messy:

```javascript
fs.readFile('users.json', (err, users) => {
  if (err) console.error(err);
  
  fs.readFile('posts.json', (err, posts) => {
    if (err) console.error(err);
    
    fs.readFile('comments.json', (err, comments) => {
      if (err) console.error(err);
      
      console.log(users, posts, comments);
      // Deep nesting = hard to read
    });
  });
});
```

Solution = use Promises or async/await.

* * *

## Promises: Better Non-Blocking Pattern

Promise = cleaner callback. Chain operations.

### What is Promise?

Promise = object that represent future value.

```javascript
const promise = fs.promises.readFile('file.txt');

promise
  .then((data) => {
    console.log('File read:', data);
  })
  .catch((err) => {
    console.error('Error:', err);
  });
```

### Promise Chain

No nesting needed:

```javascript
const fs = require('fs').promises;

fs.readFile('users.json')
  .then((users) => {
    console.log('Users loaded');
    return fs.readFile('posts.json');  // Chain next operation
  })
  .then((posts) => {
    console.log('Posts loaded');
    return fs.readFile('comments.json');
  })
  .then((comments) => {
    console.log('Comments loaded');
    console.log('All data ready');
  })
  .catch((err) => {
    console.error('Error:', err);
  });
```

Clean. Easy read.

### Promise Syntax

```javascript
new Promise((resolve, reject) => {
  // Do async work
  if (success) {
    resolve(data);  // Pass data when done
  } else {
    reject(error);  // Pass error if fail
  }
});
```

Example:

```javascript
function readFile(filename) {
  return new Promise((resolve, reject) => {
    fs.readFile(filename, (err, data) => {
      if (err) {
        reject(err);
      } else {
        resolve(data);
      }
    });
  });
}

readFile('users.json')
  .then((data) => console.log(data))
  .catch((err) => console.error(err));
```

* * *

## Async/Await: Cleanest Non-Blocking Pattern

Async/await = write async code like sync code.

### What is Async/Await?

Async/await = Promises but easier read. Look like normal code.

```javascript
async function loadData() {
  try {
    const users = await fs.promises.readFile('users.json');
    console.log('Users:', users);
    
    const posts = await fs.promises.readFile('posts.json');
    console.log('Posts:', posts);
    
  } catch (err) {
    console.error('Error:', err);
  }
}

loadData();
```

No `.then()` chains. Clean.

### Async Function

`async` keyword make function return Promise:

```javascript
async function getData() {
  return 'some data';  // Auto wrapped in Promise
}

getData().then((data) => console.log(data));  // Work with Promise
```

### Await Keyword

`await` pause function until Promise resolve:

```javascript
async function loadFile() {
  console.log('Start');
  
  const data = await fs.promises.readFile('file.txt');
  // Wait here until file ready
  // Then continue
  
  console.log('Done');
  console.log(data);
}

loadFile();
```

Timeline:

```
1. Start (print)
2. Begin reading file
3. PAUSE (await wait)
4. File ready
5. Resume
6. Done (print)
7. Print data
```

### Real Example: Async/Await

```javascript
const express = require('express');
const fs = require('fs').promises;
const app = express();

app.get('/users/:id', async (req, res) => {
  try {
    const userId = req.params.id;
    
    // Read user file
    const userFile = await fs.readFile(`users/${userId}.json`);
    const user = JSON.parse(userFile);
    
    // Read user posts
    const postsFile = await fs.readFile(`posts/${userId}.json`);
    const posts = JSON.parse(postsFile);
    
    // Return both
    res.json({ user, posts });
    
  } catch (err) {
    res.status(500).json({ error: 'Server error' });
  }
});

app.listen(3000);
```

During `await`, server handle other users. Not blocked.

* * *

## Blocking vs Non-Blocking: Side-by-Side

### File Read Comparison

**Blocking:**

```javascript
const fs = require('fs');

function readUser() {
  // This freeze whole server
  const data = fs.readFileSync('user.json');
  return data;
}

const user = readUser();
console.log(user);
```

**Non-blocking (Promise):**

```javascript
const fs = require('fs').promises;

function readUser() {
  // Return Promise
  return fs.readFile('user.json');
}

readUser()
  .then((data) => console.log(data))
  .catch((err) => console.error(err));
```

**Non-blocking (Async/Await):**

```javascript
const fs = require('fs').promises;

async function readUser() {
  try {
    const data = await fs.readFile('user.json');
    return data;
  } catch (err) {
    console.error(err);
  }
}

const user = await readUser();
console.log(user);
```

### Database Call Comparison

**Blocking (bad):**

```javascript
const user = db.getUserSync(1);  // Server freeze
res.json(user);
```

**Non-blocking (good):**

```javascript
db.getUser(1, (err, user) => {
  if (err) return res.status(500).json({ error: err });
  res.json(user);  // Server not frozen
});
```

**Non-blocking (async/await, best):**

```javascript
async function handleRequest(req, res) {
  try {
    const user = await db.getUser(1);
    res.json(user);
  } catch (err) {
    res.status(500).json({ error: err });
  }
}
```

* * *

## Real-World Examples

### Example 1: Read File and Database

**Wrong (blocking):**

```javascript
const fs = require('fs');
const db = require('./db');

app.get('/profile/:id', (req, res) => {
  // Freeze server here
  const settings = fs.readFileSync('config.json');
  const user = db.getUserSync(req.params.id);
  
  res.json({ user, settings });
});
```

Timeline for 3 users:
```
User 1: File read (2s) → DB query (3s) = 5s total
User 2: Wait... wait... wait... (5s)
User 3: Wait... wait... wait... (10s)
```

**Right (non-blocking):**

```javascript
const fs = require('fs').promises;
const db = require('./db');

app.get('/profile/:id', async (req, res) => {
  try {
    // Both start at same time (parallel)
    const [settings, user] = await Promise.all([
      fs.readFile('config.json'),
      db.getUser(req.params.id)
    ]);
    
    res.json({ user, settings });
  } catch (err) {
    res.status(500).json({ error: err });
  }
});
```

Timeline for 3 users:
```
User 1: Start both → Wait 3s → Done
User 2: Start both → Wait 3s → Done
User 3: Start both → Wait 3s → Done
Total: All 3 done in 3 seconds (not 15)
```

### Example 2: Loop with Non-Blocking

**Wrong (blocking):**

```javascript
const fs = require('fs');

function processFiles(filenames) {
  const results = [];
  
  for (const filename of filenames) {
    // Read each file one by one (SLOW)
    const data = fs.readFileSync(filename);
    results.push(data);
  }
  
  return results;
}

processFiles(['file1.txt', 'file2.txt', 'file3.txt']);
// Take 3 seconds (1s each)
```

**Right (non-blocking, parallel):**

```javascript
const fs = require('fs').promises;

async function processFiles(filenames) {
  // Read all files at same time
  const promises = filenames.map(filename => 
    fs.readFile(filename)
  );
  
  const results = await Promise.all(promises);
  return results;
}

await processFiles(['file1.txt', 'file2.txt', 'file3.txt']);
// Take 1 second (all run together)
```

### Example 3: API Call with Non-Blocking

**Wrong (blocking - would hang server):**

```javascript
// Blocking network call (doesn't exist in Node.js)
const data = http.requestSync(url);  // NO
res.json(data);
```

**Right (non-blocking):**

```javascript
const axios = require('axios');

app.get('/data', async (req, res) => {
  try {
    // Don't block - wait for response
    const response = await axios.get('https://api.example.com/data');
    res.json(response.data);
  } catch (err) {
    res.status(500).json({ error: err });
  }
});
```

Server handle 100 users at once. Each `await` not block others.

* * *

## Common Mistakes

### Mistake 1: Using Sync Methods in Production

```javascript
// ✗ Bad - freeze server
const data = fs.readFileSync('file.txt');

// ✓ Good - don't freeze
const data = await fs.promises.readFile('file.txt');
```

### Mistake 2: Forgetting Error Handling

```javascript
// ✗ Bad - error crash app
async function loadData() {
  const data = await fs.readFile('file.txt');
  console.log(data);
}

// ✓ Good - handle error
async function loadData() {
  try {
    const data = await fs.readFile('file.txt');
    console.log(data);
  } catch (err) {
    console.error('Error:', err);
  }
}
```

### Mistake 3: Sequential When Could Be Parallel

```javascript
// ✗ Bad - run one at time (3 seconds)
async function getData() {
  const users = await db.getUsers();
  const posts = await db.getPosts();
  const comments = await db.getComments();
  return { users, posts, comments };
}

// ✓ Good - run all together (1 second)
async function getData() {
  return Promise.all([
    db.getUsers(),
    db.getPosts(),
    db.getComments()
  ]);
}
```

### Mistake 4: Callback Hell (Before Understanding Promises)

```javascript
// ✗ Bad - nested and hard read
fs.readFile('file1.txt', (err, data1) => {
  fs.readFile('file2.txt', (err, data2) => {
    fs.readFile('file3.txt', (err, data3) => {
      console.log(data1, data2, data3);
    });
  });
});

// ✓ Good - use Promise.all
async function readFiles() {
  const [data1, data2, data3] = await Promise.all([
    fs.promises.readFile('file1.txt'),
    fs.promises.readFile('file2.txt'),
    fs.promises.readFile('file3.txt')
  ]);
  console.log(data1, data2, data3);
}
```

* * *

## When to Block (Rare)

Generally: don't block.

But rare cases:

1. **Server startup** - Load config before start
2. **CLI tools** - Command line tool need blocking read
3. **One-time script** - Not long-running server

```javascript
// OK to block on startup
const config = fs.readFileSync('config.json');

const app = express();
app.use(/* setup */);

// NOW use async everywhere
app.get('/data', async (req, res) => {
  const data = await getData();
  res.json(data);
});

app.listen(3000);
```

* * *

## Practice Assignment

**1. Fix blocking code:**

```javascript
// Given blocking code, rewrite with async/await
const fs = require('fs');

function loadData() {
  const users = fs.readFileSync('users.json');
  const posts = fs.readFileSync('posts.json');
  return { users, posts };
}

// Rewrite to non-blocking
```

**2. Build async API endpoint:**

```javascript
// Create Express endpoint that:
// - Read user file from disk
// - Query database for user data
// - Return combined response
// Use async/await
```

**3. Parallel operations:**

```javascript
// Write function that read 5 files
// Do NOT read one by one
// Read all at same time using Promise.all
```

**4. Error handling:**

```javascript
// Add proper try/catch
// Handle file read errors
// Handle database errors
// Return error responses
```

**5. Performance test:**

```javascript
// Create two versions:
// - Blocking (sequential read)
// - Non-blocking (parallel read)
// Test speed difference
// Measure time
```

* * *

## Quick Recap

*   **Blocking code** = wait for operation. Nothing else happen.
    
*   **Non-blocking code** = start operation, move on. Callback when done.
    
*   **Blocking freeze server**. All users wait.
    
*   **Non-blocking** allow server handle many users.
    
*   **Sync methods** = `readFileSync`, `querySync`. Avoid in production.
    
*   **Async methods** = `readFile`, `query`. Use these.
    
*   **Callbacks** = function run later. Basic async pattern.
    
*   **Promises** = cleaner callbacks. Chain operations.
    
*   **Async/await** = easiest pattern. Look like normal code.
    
*   **`async` function** = return Promise automatically.
    
*   **`await` keyword** = pause until Promise done.
    
*   **`try/catch`** = handle errors in async code.
    
*   **`Promise.all`** = run multiple async at once (parallel).
    
*   **Sequential** = one after another (slow).
    
*   **Parallel** = all together (fast).
    
*   **3 users, 5 seconds each** = blocking need 15 seconds total.
    
*   **3 users, 5 seconds each** = non-blocking do 5 seconds total.
    
*   **Most operations are I/O**: files, database, network. Use async.
    
*   **Block only on startup**, not during request handling.
    

Non-blocking code = fast servers. Fast servers = happy users.

* * *

> If you enjoyed this article, check out my other blogs on this profile. Connect with me: [LinkedIn](https://linkedin.com/in/rajharsh03) | [GitHub](https://github.com/RajHarsh03) | [X (Twitter)](https://x.com/rajharsh03)
