# Mastering Promises in JavaScript (Async, Await, Fetch Explained with Real-Life Examples)

When we start working with JavaScript seriously, one concept becomes unavoidable:

that is **Promises.**

If you understand Promises properly, you know well **Async, Await, Fetch API, API calls, and real-world applications**.

Let’s understand everything in a simple, practical way.

## Why Do We Even Need Promises?

JavaScript is single-threaded.

What it means?

*   It means, It can do one thing at a time.
    
*   But some tasks take time (API call, file read, database query).
    

Example:

*   Ordering food (we can not get food just after ordered)
    
*   Downloading a file (we can not get our file downloaded just after click on "download button")
    
*   Fetching user data from server (again same it need some time)
    

These kinds of tasks take time sometime little(milliseconds) or more.

If JavaScript waits for them, the whole application will freeze.

So instead of waiting…

JavaScript says:

> “You continue your work. I’ll inform you when the task is complete.”

That notification system is called a Promise.

## Real Life Analogy – Ordering Pizza

Imagine you order a pizza.

1.  You place an order.
    
2.  > Restaurant says: “Promise! We will deliver.”
    
3.  You don’t stand there waiting.
    
4.  After some time:
    
    *   Pizza arrives (Resolved)
        
    *   Order cancelled (Rejected)
        

That’s exactly how a Promise works.

## What is a Promise in JavaScript?

A Promise is an object that represents:

> The eventual completion (or failure) of an asynchronous operation.

It has 3 states: **Pending, Fulfilled (Resolved), Rejected**

## How to Create a Promise (new Promise)

```javascript
const myPromise = new Promise((res, rej) => {
  let success = true;

  if (success) {
    res("Task completed successfully!");
  } else {
    rej("Something went wrong!");
  }
});
```

Here `res` and `rej` represents **resolve(Success) and reject(Error)**.

## Using .then() and .catch()

```javascript
myPromise
  .then((result) => {
    console.log(result);
  })
  .catch((error) => {
    console.log(error);
  });
```

`.then()` runs when promise is resolved

`.catch()` runs when promise is rejected

## What If We Resolve “Turant” or Immediately?

```javascript
const promise = new Promise((resolve) => {
  resolve("Resolved immediately!");
});

promise.then((data) => {
  console.log(data);
});

console.log("Hello");
```

Output:

```plaintext
Hello
Resolved immediately!
```

Even if we resolve immediately, JavaScript still pushes it to the microtask queue.

That’s why synchronous code runs first.

This is part of the Event Loop mechanism. Refer the below Image.

![](https://cdn.hashnode.com/uploads/covers/69515e6c425371c0d413b409/cc45e9c6-43ce-41a6-8650-54a9519dd63d.png align="left")

## Promise Chaining

```javascript
fetchData()
  .then((data) => {
    return processData(data);
  })
  .then((processed) => {
    return saveData(processed);
  })
  .catch((error) => {
    console.log(error);
  });
```

Each `.then()` returns a new Promise.

This is called Promise chaining.

## Limit of .then()

Using too many `.then()` calls creates:

*   Callback-style pyramid
    
*   Hard-to-read code
    
*   Difficult debugging
    

Example of messy chaining:

```javascript
doTask()
  .then(result1 => doSecondTask(result1))
  .then(result2 => doThirdTask(result2))
  .then(result3 => doFourthTask(result3))
  .then(result4 => console.log(result4))
  .catch(err => console.log(err));
```

This becomes hard to maintain.

That’s why we use **Async/Await**.

## Async & Await (Cleaner Version of Promise)

Async/Await is just a cleaner way to write Promises.

```javascript
async function handleTask() {
  try {
    const result1 = await doTask();
    const result2 = await doSecondTask(result1);
    const result3 = await doThirdTask(result2);
    
    console.log(result3);
  } catch (error) {
    console.log(error);
  }
}
```

Benefits:

*   Looks synchronous
    
*   Easy to read
    
*   Easy error handling
    
*   Professional code style
    

## Fetch API + Promise

`fetch()` automatically returns a Promise.

```javascript
fetch("https://api.freeapi.app/api/v1/public/randomusers?page=1&limit=10")
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.log(error));
```

Using async/await:

```javascript
async function getUsers() {
  try {
    const response = await fetch("https://api.freeapi.app/api/v1/public/randomusers?page=1&limit=10");
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.log(error);
  }
}
getUsers();
```

Behind The Scenes **Important as per my thought**

When you use a Promise:

1.  It goes to **Web APIs (browser)**.
    
2.  After completion --> goes to **Microtask Queue**.
    
3.  Event Loop checks **Call Stack**.
    
4.  Then executes `.then()` **callback**.
    

Microtasks always run before **macrotasks** (like setTimeout).

This is why **Promise callbacks** run faster than **setTimeout**.

## Promise API Static Methods

JavaScript provides powerful static methods on the Promise object to handle multiple promises at once.

These are extremely important for real-world applications and interviews.

Let’s understand them one by one.

**Promise.all(iterable),**

```javascript
const p1 = Promise.resolve("Pizza");
const p2 = Promise.resolve("Burger");
const p3 = Promise.resolve("Pasta");

Promise.all([p1, p2, p3])
  .then(results => {
    console.log(results); 
    // ["Pizza", "Burger", "Pasta"]
  })
  .catch(error => {
    console.log(error);
  });
```

Waits for all promises to fulfil.

Rejects immediately if any promise fails.

**Promise.allSettled(iterable)**

```javascript
const p1 = Promise.resolve("Success");
const p2 = Promise.reject("Failed");

Promise.allSettled([p1, p2])
  .then(results => {
    console.log(results);
  });
```

```plaintext
// Output:
[
  { status: "fulfilled", value: "Success" },
  { status: "rejected", reason: "Failed" }
]
```

Waits for all promises to settle (Fulfilled or Rejected)

It never fails completely.

**Promise.race(iterable)**

```javascript
const p1 = new Promise(resolve =>
  setTimeout(() => resolve("First"), 2000)
);

const p2 = new Promise(resolve =>
  setTimeout(() => resolve("Second"), 1000)
);

Promise.race([p1, p2])
  .then(result => {
    console.log(result); // "Second"
  });
```

Settles as soon as the first promise settles (either resolve or reject)

**Promise.any(iterable)**

```javascript
const p1 = Promise.reject("Error 1");
const p2 = Promise.resolve("Success!");
const p3 = Promise.reject("Error 3");

Promise.any([p1, p2, p3])
  .then(result => {
    console.log(result); // "Success!"
  })
  .catch(error => {
    console.log(error);
  });
```

Fulfills as soon as **any promise fulfills**  
Rejects only if ALL promises reject

## Comparison Table

| Method | Waits For | Reject Behavior | Use Case |
| --- | --- | --- | --- |
| Promise.all | All fulfilled | Fails immediately | When everything is required |
| Promise.allSettled | All settled | Never fails completely | When you want full report |
| Promise.race | First settled | May reject first | When fastest result matters |
| Promise.any | First fulfilled | Rejects if all fail | When you need at least one success |

## Summary (What we read)

*   Promise handles async operations
    
*   Has 3 states **(Pending, Fulfilled, Rejected)**
    
*   `.then()` and `.catch()` handle result
    
*   **Async/Await** is cleaner syntax
    
*   `fetch()` returns a Promise Even immediate resolve runs asynchronously
    
*   **Event Loop** plays important role
    
*   **Promise API Static** Methods
    

## Final Real Life Summary

Promise is like:

> “I promise I will call you when the work is done.”

**Async/Await** is like:

> “Call me when the pizza arrives.”

**JavaScript becomes easier when you try things yourself.**

Thank you for reading this article.

If you found this helpful, feel free to connect with me on [**LinkedIn**](https://www.linkedin.com/in/devsantoshkumar/) and follow my journey as I continue sharing JavaScript and frontend concepts ([**more blogs**](https://devwithsantosh.hashnode.dev/)).
