Everything about Promises in JavaScript
Tags: webdev, javascript, beginners
Published: 2022-06-05 18:55:53

Hey folks! 👋 Today, in this post we will look at one of the important concepts of JavaScript and that is Promises. We will look at what is a promise, consumer methods, and promise static methods. So, let's get started. This is going to be a bit long post.

## Introduction to Promise

A promise in JavaScript is an object that represents the completion or failure of an asynchronous operation and its result. That means we always get something back from the promise, whether it will be a success value or the error value. 

A promise can be in one of the following states 

- pending - the initial state, the results are yet to be decided 
- fulfilled - represents the successful completion of the task
- rejected - represents the failure of the task 

A promise is settled when it is either fulfilled or rejected.

## Create your own promise 

We can create a promise using the promise constructor 

```js
const promise = new Promise((resolve, reject) => {
  // your asynchronous task
});
```

A new promise object is returned from the constructor. The promise constructor needs an executor function to be passed, and the `resolve` and `reject` callbacks are passed by the JavaScript itself. 

The executor function is executed immediately when `new Promise` is called. The work of the executor function is to produce a value. Whenever it gets the value, it should call `resolve` or `reject` based on the results. 

When `resolve` is called promise moves to the fulfilled state, and when `reject` is called promise moves to the rejected state. 

Now, let's do some work inside the executor function 

```js
const promise = new Promise((resolve, reject) => {
  // this function is executed immediately when a new promise is created
 
  // the promise will be resolve with value 5 after 1 second.
  setTimeout(() => {
    resolve(5);
  }, 1000);
});
```

The executor function contains an asynchronous task, the promise will be resolved with a value of 5 after 1 second. The promise object has two hidden properties `[[PromiseState]]` and `[[PromiseResult]]` which keep track of the current state of promise and the resulting value.

![Promise Object](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kq138at5eycklivrj3hv.png)
 
We can also directly resolve the promise without waiting for any action to take place. 

```js
const promise = new Promise((resolve, reject) => {
  // the promise will be resolved immediately 
  resolve(5)

  // any resolve or reject call after this will be ignored 
  reject('Error'); // ignored
})
```

That's how we create a new promise. 

## Accessing the promise results

We can not directly access the `state` and `result` property of the promise. We can access the result value using `.then`, `.catch`, and `.finally` promise methods. 

All the above methods return a new promise which means they can be further chained to do some other work based on the result of a previous promise. That is something called promise chaining. 

### then

`.then` method accepts up to two arguments. The first one is the function executed when the promise is fulfilled, the second argument is the function which executed when the promise is rejected. 

```js
promise.then((result) => {
  // here handle fulfilled promise
}, (error) => {
  // handle rejected promise
})
```

The second argument is optional. 

Let's look at the example 

```js
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(5);
  }, 1000);
});

promise.then(
  (result) => console.log(result),  // 5
  (error) => console.log(error)  // doesn't run
); 
```

Here is the reaction to the rejected promise 

```js
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("Promise rejected");
  }, 1000);
});

promise.then(
  (result) => console.log(result), // doesn' run
  (error) => console.log(error) // Promise rejected
);
```

### catch 

What if we are only interested in the errors? We can handle this in two ways, we can pass the first argument to `.then` as `null` and provide the second callback function or we can use the `.catch` method. 

The `.catch` requires a function that will be executed when the promise is rejected and get an error value as the argument. 

```js
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("Promise rejected");
  }, 1000);
});

promise.catch(
  (error) => console.log(error) // Promise rejected
);
```

### finally 

The `.finally` method requires a function that will be executed when the promise is settled. A promise is said to be settled when it is either fulfilled or rejected. 

The function passed to the `.finally` doesn't get any arguments. That means it doesn't know whether the promise is fulfilled or rejected. We can perform clean-up inside this handler like stopping the loader. 

```js
promise.finally(() => {
  // perform clean up
});
```

The resolved value or rejected value is passed through the `finally` handler. We can access the value by chaining `.then` or `.catch` to the `.finally` method. 

```js
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(5);
  }, 1000);
});

promise
  .finally(() => {
    // perform clean up
  })
  .then((result) => console.log(result)); // 5
```

This way we handle the result of the promise using `.then`, `.catch`, and `.finally`.

## Promise static methods

There are 6 static methods that we will look at. 

### Promise.all()

`Promise.all()` method allows one to process several promises in parallel and wait until all the promises are resolved. It returns a single promise that resolves the array of all promises' results. 

If any one of the promises in the list of promises passed is rejected then `Promise.all()` is immediately rejected and other promises are ignored. 

Syntax 

```js
Promise.all(iterable)
```

Here iterable is generally an array of promises.

An example, 

```js
const promise1 = new Promise((resolve) =>
  setTimeout(() => resolve("promise1"), 3000)
);

const promise2 = new Promise((resolve) =>
  setTimeout(() => resolve("promise2"), 3000)
);

const listOfPromise = [promise1, promise2];

Promise.all(listOfPromise).then((results) => console.log(results)); // ["promise1", "promise2"]
```

Note that the resulting array will get be in the same order as the input array.


### Promise.allSettled()

`Promise.all()` is rejected as a whole if one of the promises provided is rejected. But sometimes we need the result of every promise regardless of their results. That's where we can use `Promise.allSettled()` 

`Promise.allSettled()` takes an iterable of promises and returns a new Promise which is resolved to an array of objects having information about the status and value of each promise.

for the fulfilled promise, the object looks like 

```{ status: "fulfilled" , value: result }```

for the rejected promise, the object looks like 

```{ status: "rejected", value: error }```

```js
const promise1 = new Promise((resolve) =>
  setTimeout(() => resolve("promise1"), 3000)
);

const promise2 = new Promise((resolve, reject) =>
  setTimeout(() => reject("promise2"), 3000)
);

const listOfPromise = [promise1, promise2];

Promise.allSettled(listOfPromise).then((results) => console.log(results)); 

// [{status: 'fulfilled', value: 'promise1'}, {status: 'rejected', reason: 'promise2'}]
```

### Promise.any() 

`Promise.any()` takes an iterable of promises and returns the result of the promise which gets resolved as soon as possible. If none of the promises are resolved then it returns an [Aggregate Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError). 

```js
const promise1 = new Promise((resolve) =>
  setTimeout(() => resolve("promise1"), 5000)
);

const promise2 = new Promise((resolve) =>
  setTimeout(() => resolve("promise2"), 3000)
);

const listOfPromise = [promise1, promise2];

Promise.any(listOfPromise).then((result) => console.log(result));

// promise2 
```

### Promise.race() 

Just like `Promise.any()` `Promise.race()` takes an iterable of promises and wait until any one of the promises is settled and return the result or error depending upon the condition. 

```js

const promise1 = new Promise((resolve) =>
  setTimeout(() => resolve("promise1"), 5000)
);

const promise2 = new Promise((resolve, reject) =>
  setTimeout(() => reject("promise2 rejected"), 3000)
);

const listOfPromise = [promise1, promise2];

Promise.race(listOfPromise)
  .then((result) => console.log(result))
  .catch((error) => console.log(error));

// promise2 rejected
```

### Promise.resolve() 

The `Promise.resolve(value)` creates a resolved promise with the result of value. If the value is a promise then that promise is returned. 

### Promise.reject() 

The `Promise.reject(error)` creates a new promise which is rejected with the given error. 

These are the 6 static methods of promises. 

That's all for this post, thank you for reading. I hope you learned something new. 

If you have any questions, feel free to get in touch with me. 

You can connect with me on 
- [Twitter](https://twitter.com/junaidshaikh_js)
- [Linkedin](https://www.linkedin.com/in/junaidshaikhjs/)
- [Github](https://github.com/junaidshaikh-js)

I will see you in the next post. Till then, keep coding :)