Learn Promises to write Asynchronous JavaScript code
Tags: javascript, tutorial, webdev, beginners
Published: 2020-02-18 09:47:37

#### What you will learn
* Creating Promises
* Promise Executor function
* resolve and reject in Promise
* Consuming Promises
* Chaining Promises
* Catching errors in Promise

Disclaimer : I have used only arrow functions.

# Why write Async code anyway?
JavaScript is a single-threaded programming language which means only a single statement is executed at a time. This means until a statement is completely executed it will not go to the next line of code.
This is a problem if you have a code snippet that takes a long time to complete such as an API call or reading a file from the disk.

To solve this we write asynchronous JavaScript code.

# Creating New Promises

Promises are easy to create. Just create a function and return a new Promises
``` 
const longOperation = () => {
         return new Promise ()
    }
```

A promise takes an executor function as a parameter which again takes two parameters `resolve` and `reject` the code is easier to understand than my words.

    const longOperation = () => {
        return new Promise((resolve, reject) => {
            // executor function
            // your business logic here
        });
    };

## Executor function
This is the place where you would write the synchronous code (or any code) which you want to run in the background. It has two arguments `resolve` and `reject`.

### **`resolve` and `reject`**

Think of these as return statements in a function. The Executor function should execute either resolve or reject based on your business logic. When the code inside the Executor function runs like expected without any errors, then execute the **resolve** function with the value you want to return. If anything goes wrong like 'file not found' or 'network error' return the error message using the **reject** function. I hope the following code will make it clear.

    const longOperation = (a, b) => {
        return new Promise((resolve, reject) => {
            // executor function
            try {
                const result = a * b;
                resolve(result);
            } catch (error) {
                reject(`Error resolving promise ${error}`);
            }
        });
    };

#### Same example using  if..else
```
   const longOperation = (a, b) => {
        return new Promise((resolve, reject) => {
            // executor function
            const result = a * b;
            if(true){
                resolve(result);
            }
            else{
                reject(`Error resolving promise ${error}`);
            }
        });
    };
```
### Again
- `resolve(returnValue)` : Use this to return the result from successful execution of the business logic.
- `reject(errorValue)` : Use this when your logic fails and you want to throw errors. This will trigger the catch block when the function is called inside a `try...catch` block or the `.catch()` when you consume your promise.

# Consuming Promise

A promise can be consumed in two ways

1. `.then().catch()` function
2. `async / await` function

## Method 1 `.then().catch()`

This is the simplest way to consume a promise.

    longOperation(5,6).then().catch()

When the Promise `longOperation` runs without any errors the `.then()` is executed. If there are any errors, the `.catch()` is executed


    longOperation(5, 5)
        .then(result => console.log(result))
        .catch(err => console.log(err));
    
    console.log('This will be logged first'); // to demonstrate that promise is non-blocking

    Output
    This will be logged first
    25

#### Explanation
- The `.then()` is executed if longOperation executes without any error, in other words, if the Promise is `resolve`d
- The `.catch()` is executed if longOperation  `reject`s the Promise
- The `result` argument will contain the value passed to the `resolve`
- The `err` argument will contain the value passed to the `reject`

Note : The code `console.log('This will be logged first');` is only used to demonstrate that Promises are non-blocking. Though it is callafter the `longOperation` function call, it's being logged first in the console, this is because the `longOperation` returns a Promise which runs in the background which makes JS available to execute the remaining code.

## Method 2 `async / await`

Using `async / await` is like sugar-coating what we saw earlier. Instead of using `.then()` we are using a syntax which looks like synchronous code. 

    const main = async () => {
    };

* Just declare a function like you will usually do.
* Add `async` keyword before the parenthesis of the arrow function. This will allow the function to use `await` keyword inside it.

```
const main = async () => {
        try {
            const result = await longOperation(10, 2);
            console.log(result);
        } catch (error) {
            console.log(error)
        }
    };
    main()
    
    console.log('This will be logged first'); // to demonstrate that promise is non-blocking

    Output
    This will be logged first
    20
   ```

#### Explanation
The variable `result` will contain the resolved value from the promise `longOperation` (i.e) it will contain the value passed inside the `resolve()`.

When something goes wrong with `longOperation` then the catch block is executed. The error variable contains the value passed inside the `reject()` of the Promise.

Note: If you are using async...await then you should always consume promises inside a try...catch block.

# Chaining Promises

Some times you want to chain Promises (i.e) you want to execute another Promise after completion of a Promise.

### Chaining Promise using `.then()`

    longOperation(5, 5)
        .then(result => longOperation(10, result)) // multiply result by 10
        .then(result => longOperation(100, result)) // multiply result by 100
        .then(result => console.log(result)) // console log final result
        .catch(err => console.log(err));
    
    console.log('This will be logged first'); // to demonstrate that promise is non-blocking

    OUTPUT
    This will be logged first
    25000

Note: Since I'm lazy to write imaginative Promise functions, I'm using the same longOperation to mimic a new promise. In reality, you will be calling different promises after the successful execution of one. 

If any Promise in the chain throws an error then the `.catch()` is executed.

### Chaining Promise using `async / await`

    const main = async () => {
        try {
            const result1 = await longOperation(10, 5);
            const result2 = await longOperation(100, result1); // multiply result1 with 100
            const result3 = await longOperation(1000, result2); // multiply result2 with 1000
            console.log(result3); // only executed after all the Promises are resolved
        } catch (error) {
            console.log(error);
        }
    };
    
    main();
    
    console.log('This will be logged first'); // to demonstrate that promise is non-blocking

    This will be logged first
    5000000

Using async / await will make your code look tidy and readable unlike .then() in which you would have to write a lot of callbacks.

The catch block will be executed when any of the Promise throws an error.

# Catching Errors in Promise

As we saw earlier, when any of the Promise executes the `reject()` function then the catch block is executed. To demonstrate this we will create a new Promise.

    const checkAndMultiply = (a, b) => {
        return new Promise((resolve, reject) => {
            // executor function
            if (isNaN(a) || isNaN(b)) {
                const error = 'Error: inputs are not numbers';
                reject(error);
            }
            const result = a * b;
            resolve(result);
        });
    };

`checkAndMultiply` is a Promise which will only resolve if both the inputs passed to it are numbers else it will throw an error. 

    const main = async () => {
        try {
            const result1 = await longOperation(10, 5);
            const result2 = await checkAndMultiply("text", result1);
            const result3 = await checkAndMultiply(100, result2);
            console.log(result3);
        } catch (error) {
            console.log(error);
        }
    };
    
    main();
    console.log('This will be logged first');
    
    
    Output
    This will be logged first
    Error: inputs are not numbers

The first Promise `longOperation` is resolved successfully 
The second Promise `checkAndMultiply` take string as one of its argument. So the Promise is rejected and the catch block is called without executing the next Promise in the code.

I hope this article might have helped you to understand Promises in JavaScript better. You can read more about Promise from MDN Web Docs.