# From Callbacks → Callback Hell → Promises → Async/Await (JavaScript)

When I started learning async JavaScript, I was confused about how things evolved from **callbacks to async/await**.

So here’s a simple breakdown with examples

### **1\. What is a Callback?**

A callback is just a function passed into another function and executed later.

**Example**

```javascript
function xyz(text, cb) {
  cb(text);
}

xyz("shubham", (data) => {
  console.log(data);
});
```

**Output:**

```plaintext
shubham
```

**Making it Asynchronous (using setTimeout)**

```javascript
function xyz(text, cb) {
  setTimeout(() => {
    cb(text);
  }, 1000);
}

xyz("shubham", (data) => {
  console.log(data);
});
```

**Output (after 1 sec):**

```plaintext
shubham
```

* * *

### **2\. Callback Hell**

When multiple async tasks depend on each other, callbacks get nested.

**Example**

```javascript
function xyz(text, cb) {
  setTimeout(() => {
    cb(text);
  }, 1000);
}

xyz("step 1", (data1) => {
  console.log(data1);

  xyz("step 2", (data2) => {
    console.log(data2);

    xyz("step 3", (data3) => {
      console.log(data3);

      xyz("step 4", (data4) => {
        console.log(data4);
      });

    });

  });
});
```

**Problems:**

*   Hard to read
    
*   Hard to debug
    

### **Why Promises Came**

To solve callback hell, JavaScript introduced **Promises**.

* * *

### 3\. Promises Version (Clean)

```javascript
function xyz(text) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(text);
    }, 1000);
  });
}

xyz("step 1")
  .then((data1) => {
    console.log(data1);
    return xyz("step 2");
  })
  .then((data2) => {
    console.log(data2);
    return xyz("step 3");
  })
  .then((data3) => {
    console.log(data3);
    return xyz("step 4");
  })
  .then((data4) => {
    console.log(data4);
  })
  .catch(console.error);
```

**Benefits:**

*   No nesting
    
*   Better readability
    
*   Proper error handling
    

* * *

### **4\. Async/Await Version (Best & Cleanest)**

Async/Await makes async code look like normal synchronous code.

```javascript
function xyz(text) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(text);
    }, 1000);
  });
}

async function run() {
  try {
    const data1 = await xyz("step 1");
    console.log(data1);

    const data2 = await xyz("step 2");
    console.log(data2);

    const data3 = await xyz("step 3");
    console.log(data3);

    const data4 = await xyz("step 4");
    console.log(data4);
  } catch (err) {
    console.error(err);
  }
}

run();
```

**Benefits:**

*   Looks synchronous
    
*   Easy to read
    
*   Cleaner error handling
    

* * *

## 5\. await vs .then()

**Equivalent Code**

```javascript
const data = await xyz("step 1");
console.log(data);
```

**Same as:**

```javascript
xyz("step 1").then((data) => {
  console.log(data);
});
```

> await is just syntactic sugar over Promises (.then), making async code look synchronous.

* * *

### Final Summary

*   Callback → Nested (Callback Hell)
    
*   Promise → Flat chaining
    
*   Async/Await → Clean & readable
