# Async Code in Node.js: Callbacks and Promises

### 1\. Why async code exists in Node.js

*   Node.js runs on a **single-threaded event loop**
    
*   Blocking operations (like file I/O, network calls) would freeze the app
    
*   Async lets Node:
    
    *   Handle multiple tasks efficiently
        
    *   Stay responsive under load
        

* * *

### 2\. Start with a simple file reading scenario

#### Callback-based approach

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

fs.readFile('data.txt', 'utf8', (err, data) => {
  if (err) {
    console.error('Error reading file');
    return;
  }
  console.log('File content:', data);
});
```

* * *

### 3\. Callback flow (step-by-step)

1.  `readFile` is called
    
2.  Node registers the callback
    
3.  File read happens in background (non-blocking)
    
4.  Once done → callback pushed to event loop queue
    
5.  Event loop executes callback
    

* * *

### 4\. Problems with nested callbacks (Callback Hell)

```js
fs.readFile('file1.txt', 'utf8', (err, data1) => {
  if (err) return;

  fs.readFile('file2.txt', 'utf8', (err, data2) => {
    if (err) return;

    fs.readFile('file3.txt', 'utf8', (err, data3) => {
      if (err) return;

      console.log(data1, data2, data3);
    });
  });
});
```

**Issues:**

*   Hard to read 😵
    
*   Difficult error handling
    
*   Poor scalability
    
*   Pyramid-shaped code
    

* * *

### 5\. Promise-based async handling

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

fs.readFile('file1.txt', 'utf8')
  .then(data1 => {
    console.log(data1);
    return fs.readFile('file2.txt', 'utf8');
  })
  .then(data2 => {
    console.log(data2);
    return fs.readFile('file3.txt', 'utf8');
  })
  .then(data3 => {
    console.log(data3);
  })
  .catch(err => {
    console.error('Error:', err);
  });
```

* * *

### 6\. Benefits of Promises

*   Cleaner chaining (no nesting)
    
*   Centralized error handling (`.catch`)
    
*   Better readability
    
*   Easier to extend and debug
    

* * *

### 7\. Callback vs Promise (Quick Comparison)

| Aspect | Callback | Promise |
| --- | --- | --- |
| Structure | Nested | Chain-based |
| Readability | Poor (deep nesting) | Cleaner |
| Error handling | Multiple checks | Single `.catch()` |
| Scalability | Difficult | Easier |

* * *

### 8\. Flow

#### Callback Execution Chain

```plaintext
readFile → callback → readFile → callback → readFile → callback
        (nested inside each other)
```

#### Promise Lifecycle Flow

```plaintext
Pending → Fulfilled (.then)
        → Rejected (.catch)
```

* * *

### Final Suggestion

*   Avoid deep callbacks
    
*   Prefer Promises (or even better: `async/await`)
    
*   Keep async code flat and readable
