JavaScript Promises
Tags: javascript, promises, tutorial
Published: 2020-08-25 15:29:30

Often technical terminology is more closely related to English than we think. When we make a promise to someone, we say that we will do something and either do it thus resolving the promise or not thus rejecting it. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/eslcp4eursfqj1vlq8au.png)

Promises in Javascript are objects which can be expected to return a value at some point in the future.
 
####A Promise has 3 states:

- **pending:** it's initial state of neither resolved nor rejected
- **resolved:** the operation was successfully completed
- **rejected:** the operation failed

You may already be familiar with [Callback functions](https://developer.mozilla.org/en-US/docs/Glossary/Callback_function) which are functions passed into another function often used to continue code execution and achieve asynchronous JS. However, callbacks can quickly become nested and difficult to read, resulting in the affectionately named Callback Hell. Promises are syntactic sugar for achieving a similar result. Essentially, it's an object to which you attach callbacks, instead of passing callbacks into a function.

Let's jump into an example with writing our own. In this case, I have promised to write a blog about Promises!

```
let writeBlog = new Promise((resolve, reject) => {

  // writing blog 

  let blogWritten = true

  if(blogWritten){
    resolve('Completed');
  }
  else {
    reject('Failed')
  }
})

writeBlog.then(resolvedValue => {
  console.log('We are in "then" which means the promise has resolved as: ' + resolvedValue)
})

// => We are in "then" which means the promise has resolved as: Completed
```
Let's break down what is happening. 

We have defined a new Promise, `writeBlog`. The comment below this represents the code that would be executed to either resolve or reject the promise. In this instance, it resolved since we set `blogWritten` to true. We then execute the promise and call [then()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then )which is a method that returns a Promise and can take up to two arguments. We have given `then()` an argument of our value for resolve, so our log concatenates the two strings, outputting the full message.

Because `then()` returns a new Promise, it allows for chaining. For example, if we adjust the execution code above to: 

```
...
writeBlog.then(resolvedValue => {
  console.log('We are in "then" which means the promise has resolved as: ' + resolvedValue)
}).then(() => {
    console.log('This is the second "then!"')
  })

// => We are in "then" which means the promise has resolved as: Completed
This is the second "then!"
```
Here we chained a second `then()` which runs chronologically as shown in the output.

What if instead the Promise is rejected? We can use the `catch()` method which returns a Promise dealing specifically with rejected cases and takes one argument.

```
let writeBlog = new Promise((resolve, reject) => {

  // writing blog 

  let blogWritten = false

  if(blogWritten){
    resolve('Completed');
  }
  else {
    reject('Failed')
  }
})

writeBlog.then(resolvedValue => {
  console.log('We are in "then" which means the promise has resolved as: ' + resolvedValue)
}).catch(rejectedValue => {
  console.log('We are in "catch" which means the promise has ' + rejectedValue)
})

// => We are in "catch" which means the promise has Failed
```

Here we used the same code, except we changed `blogWritten` to false and chained a `catch()` to our executed Promise. As you can see, the output changes. Because the Promise rejected we see our `catch()` message.

Other methods available to Promise worth mentioning:

- `Promise.all` used when we want multiple promises to execute and wait until all of them are ready. However, it will reject as a whole if any of the Promises rejects
- `Promise.allSettled` waits for all promises to settle, regardless of the individual results
- `Promise.race` waits only for the first settled promise, regardless of the result

<hr> 

### Fetch() and Promise

`fetch()` allows us to retrieve data similar to  XMLHttpRequests and takes one required argument of a URL.

`fetch()` returns a Promise. 

Let's take a basic `fetch()` example:

```
fetch("some URL")
.then(response => response.json())
.then(data => //do something with data)
```

Remember, `fetch()` returns a Promise which we can then call `then()` on. One caveat here is that `fetch()` will always succeed even if we get something like a 404 error. The only time we will see an error in this example is if we encounter a network error. One way we can accommodate this is to check if the response is OK from within our response function.

```
fetch("some URL")
.then(response => {
   if(!response.ok) {
      console.log('Error!')
   }
   return response.json()
})
...
```
<hr> 

### Guarantees 

Promises come with a few guarantees according to MDN: 

- Attached callbacks will never be called before the completion of the current run of the JavaScript event loop, meaning that each one is processed completely before any other.
- Callbacks added with `then()` will be called even after the success or failure of the asynchronous operation.
- Multiple callbacks may be added by chaining `then()` several times. They executed one after another, in the order in which they were inserted.

<hr>

### Summary 

A Promise is an object which we expect to return a value in the future. 
A Promise is used to handle the asynchronous result of an operation.
A Promise has three states: pending, resolved, rejected.
Promises have useful methods such as [Promise.all](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all), [Promise.allSettled](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled), [Promise.race](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race)
`then()` returns a Promise.
`fetch()` returns a Promise.