DEV Community

Mahalakshmi C
Mahalakshmi C

Posted on

Promises in JavaScript

Introduction

In JavaScript, some operations take time to complete. For example, fetching data from a server, reading a file, or waiting for a timer.

JavaScript uses Promises to handle these asynchronous operations in a cleaner and more organized way.

A Promise represents the eventual result of an asynchronous operation.

A Promise can either be:

  • Successful
  • Failed
  • Still in progress

What is a Promise?

A Promise is an object that represents the result of an asynchronous operation.

For example, imagine ordering a product online.

You place the order, but the product is not delivered immediately.

The order can be:

  • Pending → Order is being processed
  • Fulfilled → Order is successfully delivered
  • Rejected → Order could not be delivered

A JavaScript Promise works in a similar way.


Why Do We Need Promises?

Before Promises, asynchronous operations were commonly handled using callbacks.

When many callbacks are nested inside each other, the code can become difficult to read and maintain.

This is called Callback Hell.

Promises provide a cleaner way to handle asynchronous operations.


Promise States

A Promise has three states:

1. Pending

The operation is still running.

2. Fulfilled

The operation completed successfully.

3. Rejected

The operation failed.

The flow is:

             Promise
                |
        -----------------
        |               |
    Fulfilled        Rejected
    (Success)        (Failure)
Enter fullscreen mode Exit fullscreen mode

A Promise starts as pending and later becomes either fulfilled or rejected.


Creating a Promise

We can create a Promise using the Promise constructor.

Syntax:

const promise = new Promise((resolve, reject) => {
    // asynchronous operation
});
Enter fullscreen mode Exit fullscreen mode

Here:

  • resolve() means the operation was successful.
  • reject() means the operation failed.

Example:

const result = new Promise((resolve, reject) => {

    let success = true;

    if (success) {
        resolve("Operation successful");
    } else {
        reject("Operation failed");
    }

});
Enter fullscreen mode Exit fullscreen mode

In this example, success is true, so the Promise is fulfilled.


Handling a Promise with then()

We use .then() to handle a successful Promise.

Example:

const result = new Promise((resolve, reject) => {

    resolve("Data received successfully");

});

result.then((message) => {
    console.log(message);
});
Enter fullscreen mode Exit fullscreen mode

Output

Data received successfully
Enter fullscreen mode Exit fullscreen mode

Explanation

The Promise calls:

resolve("Data received successfully");
Enter fullscreen mode Exit fullscreen mode

Because the operation is successful, .then() receives the result.


Handling Errors with catch()

We use .catch() to handle a rejected Promise.

Example:

const result = new Promise((resolve, reject) => {

    reject("Something went wrong");

});

result.catch((error) => {
    console.log(error);
});
Enter fullscreen mode Exit fullscreen mode

Output

Something went wrong
Enter fullscreen mode Exit fullscreen mode

Explanation

The Promise calls:

reject("Something went wrong");
Enter fullscreen mode Exit fullscreen mode

Since the Promise is rejected, .catch() handles the error.


then() and catch() Together

We can use .then() for success and .catch() for failure.

Example:

const payment = new Promise((resolve, reject) => {

    let paymentSuccessful = true;

    if (paymentSuccessful) {
        resolve("Payment successful");
    } else {
        reject("Payment failed");
    }

});

payment
    .then((message) => {
        console.log(message);
    })
    .catch((error) => {
        console.log(error);
    });
Enter fullscreen mode Exit fullscreen mode

Output

Payment successful
Enter fullscreen mode Exit fullscreen mode

If we change:

let paymentSuccessful = false;
Enter fullscreen mode Exit fullscreen mode

The output will be:

Payment failed
Enter fullscreen mode Exit fullscreen mode

Promise with Success and Failure

We can also use a condition inside a Promise.

Example:

const server = new Promise((resolve, reject) => {

    let serverWorking = true;

    setTimeout(() => {

        if (serverWorking) {
            resolve("Server connected");
        } else {
            reject("Server connection failed");
        }

    }, 2000);

});

server
    .then((message) => {
        console.log(message);
    })
    .catch((error) => {
        console.log(error);
    });
Enter fullscreen mode Exit fullscreen mode

Output

Server connected
Enter fullscreen mode Exit fullscreen mode

If:

let serverWorking = false;
Enter fullscreen mode Exit fullscreen mode

the output will be:

Server connection failed
Enter fullscreen mode Exit fullscreen mode

finally()

.finally() executes whether the Promise is fulfilled or rejected.

Example:

const processData = new Promise((resolve, reject) => {

    resolve("Data processed");

});

processData
    .then((message) => {
        console.log(message);
    })
    .catch((error) => {
        console.log(error);
    })
    .finally(() => {
        console.log("Process completed");
    });
Enter fullscreen mode Exit fullscreen mode

Output

Data processed
Process completed
Enter fullscreen mode Exit fullscreen mode

Even if the Promise is rejected, finally() will still execute.


Promise Chaining

One of the useful features of Promises is Promise chaining.

We can use multiple .then() methods one after another.

Example:

const process = new Promise((resolve, reject) => {

    resolve(10);

});

process
    .then((number) => {
        console.log(number);
        return number * 2;
    })
    .then((number) => {
        console.log(number);
        return number + 5;
    })
    .then((number) => {
        console.log(number);
    });
Enter fullscreen mode Exit fullscreen mode

Output

10
20
25
Enter fullscreen mode Exit fullscreen mode

How it works

First:

resolve(10);
Enter fullscreen mode Exit fullscreen mode

The first .then() receives 10.

return number * 2;
Enter fullscreen mode Exit fullscreen mode

So it returns 20.

The next .then() receives 20.

return number + 5;
Enter fullscreen mode Exit fullscreen mode

So it returns 25.

The final .then() receives 25.

This is called Promise Chaining.


Promise vs Callback

A callback passes a function to another function.

Example:

function getData(callback) {

    setTimeout(() => {
        callback("Data received");
    }, 2000);

}

getData((message) => {
    console.log(message);
});
Enter fullscreen mode Exit fullscreen mode

With a Promise:

function getData() {

    return new Promise((resolve) => {

        setTimeout(() => {
            resolve("Data received");
        }, 2000);

    });

}

getData()
    .then((message) => {
        console.log(message);
    });
Enter fullscreen mode Exit fullscreen mode

Promises can make multiple asynchronous operations easier to organize, especially when chaining several steps.


Real-World Uses of Promises

Promises are commonly used when working with:

  • API requests
  • Fetching data from a server
  • Database operations
  • File operations
  • Timers
  • Network requests
  • Authentication
  • Loading external data

For example, when a website requests user information from a server, the response may take some time. A Promise can represent that pending operation and later provide either the data or an error.

Promise Flow

The overall flow can be remembered like this:

Create Promise
      ↓
   Pending
      ↓
  Operation
   /      \
Success   Failure
   ↓        ↓
resolve   reject
   ↓        ↓
 .then()  .catch()
      \    /
       ↓
   .finally()
Enter fullscreen mode Exit fullscreen mode

Conclusion

Promises are used in JavaScript to handle asynchronous operations in a cleaner way.

A Promise has three states:

Pending → Fulfilled
Pending → Rejected
Enter fullscreen mode Exit fullscreen mode

The important methods are:

.then()     → handles success
.catch()    → handles errors
.finally()  → runs after completion
Enter fullscreen mode Exit fullscreen mode

Promises are especially useful for API calls, network requests, timers, and other operations that take time to complete.

Promises also provide the foundation for async/await, which gives us another clean way to work with asynchronous JavaScript.

Top comments (0)