Promises in JavaScript
Tags: promises, javascript, asynchronous, async
Published: 2020-07-19 18:45:52

## Introduction
Callbacks are functions that run after something happens or something completes. If you have to make an asynchronous request, it can either be successful or result in failure. These two possibilities in Promises are denoted by `resolves` or `rejects` parameters. 

Promises help us avoid what's commonly referred to as "callback hell", wherein cascading callbacks create a pyramid shape and impossible to decipher code that's hard to scale. Promises allow us to easily chain callbacks in an intuitive way, by chaining `then` and using `catch` for errors. Promises helps to break up callbacks into methods with semantic naming. 

## A Simple Promise
```javascript
const promise = new Promise(function (resolve, reject) {
  const a = 'apples';
  const b = 'apples';
  if (a === b) {
    resolve();
  } else {
    reject();
  }
});

promise
  .then(function () {
    console.log('success');
  })
  .catch(function () {
    console.log('error');
  });

// output => 'success'
```
## Concepts to Know
* **Deferred** objects are works that are not yet completed
* **Promise** properties are placeholders. Initially, this value is unknown.
* Each **deferred** has a **promise** which acts as a placeholder for the future result.

## Support
All modern browsers support Promises, except for Internet Explorer 11 and previous versions.
![Alt Text](https://ivanjov.com/content/images/2017/02/Screenshot-2017-02-01-15.59.57.png)

## API Request Example with Promises
Let's pretend that we have a website with multiple accounts created for people's pets. Below, we create a promise to request a made up api server a specified number of pets' user accounts. If the statusCode associated with the request is 200, that indicates that the request was successful, and that we should call `resolves` to utilize `JSON.parse` to parse the results. If we do not receive a 200 statusCode back, `rejects` is called, showing the user the failing statusCode.
```javascript
// creating the request

const getPets = (number) => {
  new Promise((resolves, rejects) => {
    const request = new XMLHttpRequest();
    request.open("GET", `https://api.examplepet.com/?results=${number}`);
    request.onload = () => {
      if (request.status === 200) {
        resolves(JSON.parse(request.response).results);
      } else {
        rejects(Error(request.statusText));
      }
      request.onerror = (error) => rejects(error);
      request.send();
    };
  });
};

// invoking the request
getPets(20)
  .then((pets) => console.log(pets))
  .catch((error) => console.error(error));

```

## Promise Method: done()
Normally, when chaining method calls with Promises, you can risk discarding errors without seeing them:

```javascript
function promisesExampleFunction() {
  asyncFunc()
  .then(function1)
  .catch(response1)
  .then(function2);
}
```
If the last `.then(function2);` line elicits a rejection, it is never handled. We can account for this using `done()` like so:
```javascript
function promisesExampleFunction() {
  asyncFunc()
  .then(function1)
  .catch(response1)
  .done(function2);
}
```
In the example above, `done()` can actually replace the last `.then(function2);`, or it can be interchangeably added after the last `.then(function2)` with `done()` receiving no arguments.

## Promise Method finally()
`finally()` is great for performing actions regardless of whether an error occurs. It is most frequently used as a clean up method after the last `then()` or `done()` call. This can be done during page loads to show and hide the spinner, regardless of whether the above functions were successful or not - you'll want to stop the spinner if processing is no longer occurring:

```javascript
spinnerShow();
fetchData()
  .then((data) => renderPage(data))
  .catch(error)
  .finally(spinnerHide);
```

## Promisify

[Promisify](http://bluebirdjs.com/docs/api/promise.promisify.html) is an easy way to convert callback functions to a function that returns Promises. Below, we convert a callback-based function called `func` to return native Promises.

```javascript
const promisify = require("es6-promisify");
const fs = require("fs");
 
const promisifiedFunc = promisify(fs.func);
 
promisifiedFunc("oranges.txt").then(function (fruit) {
  console.log("Fruit received:", fruit);
}).catch(function (error) {
  console.error(error);
});
```

## Conclusion
Promises after they're called upon eventually either `resolve` or `reject`, returning a response based on what the Promise object specifies. By chaining `then` and using `catch` for errors, we can perform asynchronous functions in an intuitive way and avoid "callback hell". Promises can handle multiple async operations seamlessly, while at the same time providing superior error handling than would be possible with simple callback chaining.