# Async Code in Node.js: Callbacks and Promises

Imagine your server is a busy restaurant waiter. If he stops everything to wait for one customer's order from the kitchen, all other tables suffer. Node.js async programming lets him take more orders while the kitchen works in the background.

## Why Node.js Needs Async Code

Node.js runs on a **single thread**. One slow task blocks everything—like `readFileSync()` waiting for a huge file.

**Blocking Example:**

```javascript
const fs = require("fs");
const data = fs.readFileSync("bigfile.txt", "utf-8"); // App freezes here
console.log(data);
console.log("Done"); // Only runs AFTER file finishes
```

**Non-blocking Magic:**

```javascript
const fs = require("fs");
console.log("Start");

fs.readFile("bigfile.txt", "utf-8", (err, data) => {
    console.log(data);
});

console.log("Done immediately!");
// Output: Start → Done immediately! → File content (later)
```

Node.js hands slow tasks to the **OS** and keeps running. Results come back via **callbacks**.

## How Callbacks Work

A callback is a function you pass to another function: *"Run me when you're done."*

**Simple Example:**

```javascript
function makeCoffee(name, callback) {
    console.log(`Making coffee for ${name}...`);
    callback("Coffee ready!");
}

function drinkCoffee(message) {
    console.log(message);
}

makeCoffee("Sharath", drinkCoffee);
// Hello Sharath
// Coffee ready!
```

**Node.js Pattern:** `(error, result) => {}`

```javascript
fs.readFile("data.txt", "utf-8", (err, data) => {
    if (err) return console.error(err);
    console.log(data);
});
```

**Key:** Callback runs **later**, after Node.js handles other requests.

## The Callback Hell Problem

Multiple dependent async calls create **pyramid of doom**:

```javascript
fs.readFile("users.txt", (err, users) => {
    fs.readFile("orders.txt", (err, orders) => {
        fs.readFile("payments.txt", (err, payments) => {
            // Finally do something with all data
            console.log("All loaded!");
        });
    });
});
```

**Problems:**

*   **Unreadable**: Code shifts right like a bad novel
    
*   **Error Hell**: `if (err) return;` everywhere
    
*   **Debug Nightmare**: Stack traces make no sense
    
    ![](https://cdn.hashnode.com/uploads/covers/695a275cee3d7756437f49db/39b2f368-cdc0-4f19-808e-df16111f101a.png align="center")
    

## Promises: The Clean Fix

**Promise** = Future value container. Three states: `pending` → `fulfilled`/`rejected`.

**Single File Example:**

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

fs.readFile("data.txt", "utf-8")
    .then(data => console.log(data))
    .catch(err => console.error(err));
```

## Promise Chaining vs Callback Hell

**Callback Hell:**

```javascript
fs.readFile("users.txt", (err, u) => {
    fs.readFile("orders.txt", (err, o) => {
        console.log(u, o);
    });
});
```

**Promise Heaven:**

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

fs.readFile("users.txt", "utf-8")
    .then(users => {
        console.log(users);
        return fs.readFile("orders.txt", "utf-8");
    })
    .then(orders => console.log(orders))
    .catch(err => console.error(err));
```

**Cleaner, flatter, one error handler!**

## Promise Superpowers

| Feature | Callback | Promise |
| --- | --- | --- |
| **Readability** | Deep nesting | Flat chain |
| **Error Handling** | Copy-paste `if(err)` | Single `.catch()` |
| **Chaining** | Manual nesting | `.then()` links |
| **Debugging** | Confusing stacks | Clear flow |

![](https://cdn.hashnode.com/uploads/covers/695a275cee3d7756437f49db/029da2d1-e035-4a6c-b34f-80ec5375ddd5.png align="center")

## The Complete Flow

```typescript
1. Trigger async → Returns Promise immediately
2. Continue other work  
3. Promise settles → .then()/.catch() runs
4. Chain next async → Repeat
```

## Real-World Example: API Chain

```javascript
app.get('/user/:id', async (req, res) => {
    try {
        const user = await getUser(req.params.id);
        const orders = await getOrders(user.id);
        const total = await calculateTotal(orders);
        
        res.json({ user, orders, total });
    } catch (err) {
        res.status(500).json({ error: err.message });
    }
});
```

## Async Evolution Summary

1.  **Callbacks** → Invented async (good start)
    
2.  **Promises** → Fixed callback hell (game changer)
    
3.  **Async/Await** → Promises + sugar syntax (today's standard)
