Understanding Promise in JavaScript
Tags: webdev
Published: 2023-08-26 07:42:20


As per MDN Web Docs, **A <u>promise</u> is an object representing the eventual completion or failure of an asynchronous operation.**

Let’s make it a bit simpler.

Consider JavaScript promise like a real-world promise where **JavaScript promises us that it will give us something after an asynchronous task has been completed**.

Asynchronous  operation/task can be one of the following:

- Fetching data from server
- Reading a file
- Writing to a file
- Reading/Writing to a database

### What did promise solve?

Before promises, job of handling asynchronous tasks was handled by **Callbacks** solely but that approach created **Pyramid of Doom** or **Callback Hell**  down the line, due to which the code becomes more of a spaghetti and nearly impossible to manage. You can check my previous article to know more about this in detail [here](https://dev.to/shameel/callback-callback-hell-promise-chaining-and-asyncawait-in-javascript-120i).

### How does Promise work?

We will break it down to two main concerns:

1. Promise Creation.
2. Promise Consumption.

### Promise Creation:

You create a promise like this:

`new Promise((resolve,reject)=>{})`

It accepts a callback function with `resolve` and `reject`.

Here is a short snippet about how it works:

```jsx
const myPromise = new Promise((resolve, reject) => {
  // Asynchronous operation, e.g., fetching data from a server
});
```

If the code is successful, then call `resolve` else, call `reject`.

Emulating the example like this:

```jsx
const fetchData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const data = { id: 1, name: 'John' };
      // Simulate success
      // resolve(data); // Uncomment this line to resolve the promise

      // Simulate error
      reject(new Error('Failed to fetch data')); // Comment out if resolving
    }, 1000); // Simulated delay of 1 second
  });
};
```

We used `setTimeout` to emulate a delay in response of fetching the data.

A **somewhat** real world example of **creating a promise** is like this:

```jsx
const authenticateUser = (username, password) => {
  return new Promise((resolve, reject) => {
    // Simulate authentication by checking against hardcoded values
    const validUsername = 'user123';
    const validPassword = 'pass456';

    setTimeout(() => {
      if (username === validUsername && password === validPassword) {
        resolve('Authentication successful');
      } else {
        reject(new Error('Authentication failed'));
      }
    }, 1000); // Simulated delay of 1 second
  });
};

```

What we have done is created an arrow function `authenticationUser` which accepts `username` and `password` which returns a `promise`. If you enter valid username and password as described in the code `user123` and `pass456` then it will return you `Authentication successful` otherwise it will return `Authentication failed`.

We learned how to create the promise. We will now move forward to the consumption of the promise.

### Promise Consumption:

Consumption of a promise require `then` for `resolving` and `catch` for `rejection` of a promise.

We can call `fetchData` that we made earlier like this:

```jsx
fetchData()
  .then(result => {
    console.log('Data fetched:', result);
  })
  .catch(error => {
    console.error('Error:', error.message);
  });
```

You can consume **authenticateUser promise** like this:

```jsx

// Usage
authenticateUser('user123', 'pass456')
  .then(message => {
    console.log(message);
  })
  .catch(error => {
    console.error('Error:', error.message);
  });
```

Check it out directly in the browser. Open `console` and then paste the above snippet:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w0ro0luyfqheaagce4f7.png)

You can see in browser console that, at first the state of `promise` appeared to be `pending` and after it was `resolved`, you saw the result.
You can try this with wrong username and password at your end to test it out.


### Promise .finally Method:

This method is always executed whether the promise is resolved or rejected.


**Code:**

I urge you to try these examples directly in your browser to check them out quickly if you do not have JS environment up and running.

```jsx
function simulateAsyncOperation(success) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (success) {
        resolve("Operation succeeded!");
      } else {
        reject(new Error("Operation failed."));
      }
    }, 1000);
  });
}

function performOperation(success) {
  simulateAsyncOperation(success)
    .then(result => {
      console.log("Resolved:", result);
    })
    .catch(error => {
      console.error("Rejected:", error.message);
    })
    .finally(() => {
      console.log("Finally block executed.");
    });
}

```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9gi3euzubetdan8kkwuw.png)



```jsx
// Call the function with success set to true for resolved path
performOperation(true);
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/upq4it25iqq4yvirdd9f.png)

```jsx
// Call the function with success set to false for rejected path
performOperation(false);
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e2znrtc2xndqdn21d4qp.png)

You can further check the process of `finally` with below textual diagrams.

**Resolved to Finally:**
```jsx
   +-------------------------+
   |                         |
   |     Initial State       |
   |                         |
   +-------------------------+
               |
               | Promise is
               | created
               |
               v
   +-------------------------+
   |                         |
   |   Pending State         |
   |                         |
   +-------------------------+
               |
               | Asynchronous
               | operation
               |
               v
   +-------------------------+
   |                         |
   |   Fulfilled State       |
   |  (Resolve Callback)     |
   +-------------------------+
               |
               | Promise is
               | resolved
               |
               v
   +-------------------------+
   |                         |
   |    Finally Block        |
   |    (Always Executed)    |
   +-------------------------+
```

**Rejected to Finally:**

```jsx
   +-------------------------+
   |                         |
   |     Initial State       |
   |                         |
   +-------------------------+
               |
               | Promise is
               | created
               |
               v
   +-------------------------+
   |                         |
   |   Pending State         |
   |                         |
   +-------------------------+
               |
               | Asynchronous
               | operation
               |
               v
   +-------------------------+
   |                         |
   |    Rejected State       |
   |   (Reject Callback)     |
   +-------------------------+
               |
               | Promise is
               | rejected
               |
               v
   +-------------------------+
   |                         |
   |    Finally Block        |
   |    (Always Executed)    |
   +-------------------------+
```

### Promise Chaining:

Promise chaining allows you to execute multiple asynchronous operations in sequence, where the result of one operation becomes the input for the next operation. This is a way to solve _Callback Hell_. 

Let’s take this example:

```jsx
function asyncOperation(data) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (data) {
        resolve(data.toUpperCase());
      } else {
        reject("No data provided");
      }
    }, 1000);
  });
}
```

This is how we can perform **Promise Chaining** i.e., by feeding the `returning a promise` in `then` statement. 

```jsx
asyncOperation("shameel")
  .then(result => {
    console.log(result); // Output: "SHAMEEL"
    return asyncOperation("uddin");
  })
  .then(result => {
    console.log(result); // Output: "UDDIN"
  })
  .catch(error => {
    console.error(error);
  });
```

We thoroughly discussed it [here](https://dev.to/shameel/callback-callback-hell-promise-chaining-and-asyncawait-in-javascript-120i).

### Conclusion

We learned how to create a promise as well as how to consume a promise in this blog and associated methods with it.

### What’s Next?

In the next blog, we will discover and deep dive into various promise methods. Understanding and utilizing these methods will enable you to effectively manage asynchronous operations and build more robust and maintainable code using promises.

Follow me here for more stuff like this:
LinkedIn: https://www.linkedin.com/in/shameeluddin/
Github: https://github.com/Shameel123