Introduction to JavaScript Promises and Async Programming
Tags: javascript, beginners, tutorial, webdev
Published: 2020-01-04 21:17:07

**Subscribe to my email list now at http://jauyeung.net/subscribe/**

**Follow me on Twitter at https://twitter.com/AuMayeung**

**Many more articles at https://medium.com/@hohanga**

Because JavaScript is a single-threaded language, synchronous code can only be executed one line at a time. This means that if there’s synchronous code that runs longer than instantaneously, then it will stop the rest of the code from running until whatever is being run is finished. To prevent code that runs for an indeterminate amount of time from holding up other code from running, we need to have asynchronous code.

* * *

Promises
========

To do this in JavaScript, we can use promises in our code. Promises are objects that represent a process that runs for an indeterminate amount of time and may result in success or failure. To create promises in JavaScript, we use a `Promise` object that’s a constructor for creating promises. The `Promise` constructor takes a function called the executor function that has the `resolve` and `reject` parameters. Both parameters are functions that we call to either fulfill the promise (which means end it successfully with some value) or to reject the promise (which means returning some error value and marking the promise as failed). The function’s return value is ignored. Therefore, promises can’t return anything other than promises.

For example, we can define a promise in JavaScript like in the following code:

```javascript
const promise = new Promise((resolve, reject) => {  
  setTimeout(() => resolve('abc'), 1000);  
});
```

The code above creates a promise that fulfills the promise with the value `abc` after one second. Because we’re running `setTimeout` inside the executor function to resolve the promise with the value `abc` in one second, it’s asynchronous code. We can’t return the value `abc` within the callback function of `setTimeout`, so we have to call `resolve('abc')` to get the resolved value back. We can access the resolved value of the fulfilled promise by using the `then` function. The `then` function takes a callback function that takes the resolved value of the fulfilled promise as a parameter. You can get the value there and do what you want with it. For example, we can do something like:

```javascript
const promise = new Promise((resolve, reject) => {  
  setTimeout(() => resolve('abc'), 1000);  
});

promise.then((val) => {  
  console.log(val);  
})
```

When we run the code above, we should see `abc` logged. As we can see, the promise will supply the value when the promise is fulfilled with a call to the `resolve` function.

A promise has three states. It can be pending, which means that the promise has been fulfilled or rejected. It can be fulfilled, which means that the operation completed successfully. Or it can be rejected, which means that the promise operation failed.

A pending promise can either be fulfilled with a value or be rejected with some error. When a promise is fulfilled, then the corresponding resolve value is picked up by the `then` function and the callback function passed into the `then` function is called. If a promise is rejected, then we can optionally catch the error with the `catch` function, which also takes a callback function with the error. Both the `then` and `catch` functions return promises, so they can be chained together.

For example, we can write something like:

```javascript
const promise = (num) => {  
  return new Promise((resolve, reject) => {  
    setTimeout(() => {  
      if (num === 1) {  
        resolve('resolved')  
      } else {  
        reject('rejected')  
      }  
    }, 1000);  
  });  
}

promise(1)  
  .then((val) => {  
    console.log(val);  
  })  
  .catch((error) => {  
    console.log(error);  
  })promise(2)  
  .then((val) => {  
    console.log(val);  
  })  
  .catch((error) => {  
    console.log(error);  
  })
```

In the code above, we have a function `promise` that returns a JavaScript promise that fulfills the promise with the value `resolved` when `num` is 1, and reject the promise with error `rejected` otherwise. So we run:

```javascript
promise(1)  
  .then((val) => {  
    console.log(val);  
  })  
  .catch((error) => {  
    console.log(error);  
  })
```

Then the `then` function runs, the promise returned by the `promise(1)` function call is fulfilled since `num` is 1, and the resolved value is available set in `val`. So when we run `console.log(val)` we get `resolved` logged. When we run the code below:

```javascript
promise(2)  
  .then((val) => {  
    console.log(val);  
  })  
  .catch((error) => {  
    console.log(error);  
  })
```

Then the `catch` function runs because the promise returned by the `promise(2)` function call is rejected, and the rejected error value is available set in error. So when we run `console.log(error)` we get `rejected` logged.

A JavaScript promise object has the following properties: `length` and `prototype`. The `length` always has its value set to 1 for the number of constructor arguments, which is always one. The `prototype` property represents the prototype of the promise object.

A promise also has the `finally` method to run code that’s run no matter whether the promise is fulfilled or rejected. The `finally` method takes a callback function as an argument, where any code that you want to run, regardless of the outcome of the promise, is run. For example, if we run:

```javascript
Promise.reject('error')  
  .then((value) => {  
    console.log(value);  
  })  
  .catch((error) => {  
    console.log(error);  
  })  
  .finally(() => {  
    console.log('finally runs');  
  })
```

Then we get `error` and `finally runs` logged because the original promise was rejected with the reason `error`. Then whatever code in the callback of the `finally` method runs.

The main benefit of using promises for writing asynchronous code is that we can use them to run asynchronous code sequentially. To do this, we can chain promises with the `then` function. The `then` function takes a callback function that runs when the promise is fulfilled. It also takes a second argument when the promise is rejected. To chain promises, we have to return another promise as the return value of the first callback function of the `then` function. It can return other values, like nothing, if we don’t want to chain another promise to the existing promise. We can return a value, which will be resolved and the value retrievable in the next `then` function. It can also throw an error. Then the promise returned by `then` gets rejected with the thrown error as the value. It can also return an already fulfilled or rejected promise, which will get the fulfilled value when a `then` function is chained after it or get an error reason in the callback of the `catch` function.

For example, we can write the following:

```javascript
Promise.resolve(1)  
  .then(val => {  
    console.log(val);  
    return Promise.resolve(2)  
  })  
  .then(val => {  
    console.log(val);  
  })Promise.resolve(1)  
  .then(val => {  
    console.log(val);  
    return Promise.reject('error')  
  })  
  .then(val => {  
    console.log(val);  
  })  
  .catch(error => console.log(error));Promise.resolve(1)  
  .then(val => {  
    console.log(val);  
    throw new Error('error');  
  })  
  .then(val => {  
    console.log(val);  
  })  
  .catch(error => console.log(error));
```

In the first example, we chained the promises and they all resolve to a value. All the promises were already resolved into values. In the second and last examples, we reject the second promise or throw an error. They both do the same thing. The second promise is rejected, and the error reason will be logged in the callback of the `catch` function. We can also chain pending promises, like in the following code:

```javascript
const promise1 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(1), 1000);  
});

const promise2 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(2), 1000);  
});

promise1  
  .then(val => {  
    console.log(val);  
    return promise2;  
  })  
  .then(val => {  
    console.log(val);  
  })  
  .catch(error => console.log(error));
```

The callback of the first `then` function returned `promise2`, which is a pending promise.

* * *

Methods
=======

JavaScript promises have the following methods.

Promise.all(iterable)
---------------------

`Promise.all` takes an iterable object that lets us run multiple promises in parallel in some computers and serially in other computers. This is handy for running multiple promises that don’t depend on each other’s values. It takes in an iterable with a list of promises, usually an array, and then returns a single `Promise` that’s resolved when the promises that are in the iterable are resolved.

For example, we can write code like the following to run multiple promises with `Promise.all`:

```javascript
const promise1 = Promise.resolve(1);  
const promise2 = 2;  
const promise3 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(3), 1000);  
});  
Promise.all([promise1, promise2, promise3])  
  .then((values) => {  
    console.log(values);  
  });
```

If we run the code above, then the `console.log` should log `[1,2,3]`. As we can see, it only returns a resolved value after all the promises are fulfilled. If some of them are rejected, then we won’t get any resolved value. Instead, we will get whatever error value is returned by the rejected promises. It will stop at the first rejected promise and send that value to the callback of the `catch` function. For example, if we have:

```javascript
const promise1 = Promise.resolve(1);  
const promise2 = Promise.reject(2);  
const promise3 = new Promise((resolve, reject) => {  
  setTimeout(() => reject(3), 1000);  
});  
Promise.all([promise1, promise2, promise3])  
  .then((values) => {  
    console.log(values);  
  })  
  .catch(error => {  
    console.log(error);  
  });
```

Then we get 2 logged from the `console.log` in the callback of the `catch` function.

`Promise.allSettled`
--------------------

`Promise.allSettled` returns a promise that resolves after all the given promises are resolved or rejected. It takes an iterable object with a collection of promises, for example, an array of promises. The resolved value of the returned promise is an array of the final status of each promise. For example, suppose we have:

```javascript
const promise1 = Promise.resolve(1);  
const promise2 = Promise.reject(2);  
const promise3 = new Promise((resolve, reject) => {  
  setTimeout(() => reject(3), 1000);  
});  
Promise.allSettled([promise1, promise2, promise3])  
  .then((values) => {  
    console.log(values);  
  })
```

If we run the code above, then we get an array with three entries, with each entry being an object that has the `status` and `value` properties for the fulfilled promises and an object that has the `status` and `reason` properties for the rejected promises. For example, the code above will log `{status: “fulfilled”, value: 1}`, `{status: “rejected”, reason: 2}`, `{status: “rejected”, reason: 3}` . The `fulfilled` status is logged for the successful promises and the`rejected` status for the rejected ones.

`Promise.race`
--------------

The `Promise.race` method returns a promise that resolves to the resolved value of the promise that’s fulfilled first. It takes an iterable object with a collection of promises, for example, an array of promises. If the iterable passed in is empty, then the returned promise will forever be pending. If the iterable object contains one or more non-promise values or already settled promises, then `Promise.race` will return to the first of these entries. For example, if we have:

```javascript
const promise1 = Promise.resolve(1);  
const promise2 = Promise.resolve(2);  
const promise3 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(3), 1000);  
});  
Promise.race([promise1, promise2, promise3])  
  .then((values) => {  
    console.log(values);  
  })
```

Then we see that `1` is logged. That’s because `promise1` is the first one that’s resolved since it’s resolved instantaneously before the next lines are run. Likewise, if we have a non-promise value in the array that we pass in as the argument, like in the following code:

```javascript
const promise1 = 1;  
const promise2 = Promise.resolve(2);  
const promise3 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(3), 1000);  
});  
Promise.race([promise1, promise2, promise3])  
  .then((values) => {  
    console.log(values);  
  })
```

Then we get the same thing logged since it’s the non-promise value in the array that we pass into the `Promise.race` method. Synchronous code always runs before the asynchronous code, so it doesn’t matter where the synchronous code is. If we have:

```javascript
const promise1 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(1), 2000);  
});

const promise2 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(2), 1000);  
});

const promise3 = 3;  
Promise.race([promise1, promise2, promise3])  
  .then((values) => {  
    console.log(values);  
  })
```

Then we get `3` logged since `setTimeout` puts the callback function in the queue to be run later, so it’s going to be run later than the synchronous code.

Finally, if we have:

```javascript
const promise1 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(1), 2000);  
}); 
 
const promise2 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(2), 1000);  
});

Promise.race([promise1, promise2])  
  .then((values) => {  
    console.log(values);  
  })
```

Then we get `2` in the console log because a promise that’s resolved in one second is going to be resolved earlier than a promise resolved in two seconds.

`Promise.reject`
----------------

`Promise.reject` returns a promise that’s rejected with a reason. It’s useful to reject a promise with an object that’s an instance of `Error`. For example, if we have the following code:

```javascript
Promise.reject(new Error('rejected'))  
  .then((value) => {  
    console.log(value);  
  })  
  .catch((error) => {  
    console.log(error);  
  })
```

Then we get `rejected` logged.

`Promise.resolve`
-----------------

`Promise.resolve` returns a promise that’s resolved to the value that’s passed into the argument of the `resolve` function. We can also pass in an object with the `then` property where the value of it is the callback function of a promise. If the value has a `then` method, then the promise will be fulfilled with the value fulfilled by the `then` function. That is, the first parameter of the function for the value of the `then` function is the same as `resolve`, and the second parameter is the same as `reject.` For example, we can write the following:

```javascript
Promise.resolve(1)  
  .then((value) => {  
    console.log(value);  
  })
```

Then we get `1` logged since `1` is the value we passed into the `resolve` function to return the promise with resolved value `1`.

If we pass in an object with a `then` method inside, like in the following code:

```javascript
Promise.resolve({  
    then(resolve, reject) {  
      resolve(1);  
    }  
  })  
  .then((value) => {  
    console.log(value);  
  })
```

Then we get value `1` logged. That’s because the `Promise.resolve` function will run the `then` function, and the `resolve` parameter for the function set to the `then` property will be assumed to be a function that’s called the `resolve` function in a promise. If we instead called the `reject` function inside the `then` function in the passed-in object, then we get a rejected promise, like in the following code:

```javascript
Promise.resolve({  
    then(resolve, reject) {  
      reject('error');  
    }  
  })  
  .then((value) => {  
    console.log(value);  
  })  
  .catch((error) => {  
    console.log(error);  
  })
```

In the code above, we get `error` logged since the promise is rejected.

* * *

Async and Await
===============

With `async` and `await`, we can shorten the promise code. Before `async` and `await`, we had to use the `then` function and we had to put callback functions as an argument of all of our `then` functions. This makes the code long as we have lots of promises. Instead, we can use the `async` and `await` syntax to replace the `then` function and its associated callbacks. For example, we can shorten the following code from:

```javascript
const promise1 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(1), 2000);  
});

const promise2 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(2), 1000);  
});

promise1  
  .then((val1) => {  
    console.log(val1);  
    return promise2;  
  })  
  .then((val2) => {  
    console.log(val2);  
  })
```

to:

```javascript
const promise1 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(1), 2000);  
});  

const promise2 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(2), 1000);  
});

(async () => {  
  const val1 = await promise1;  
  console.log(val1)  
  const val2 = await promise2;  
  console.log(val2)  
})()
```

We replaced the `then` and callbacks with `await`. Then we can assign the resolved values of each promise as variables. Note that if we use `await` for our promise code, then we have to put `async` in the function signature as we did in the above example. To catch errors, instead of chaining the `catch` function at the end, we use the `catch` clause. Also, instead of chaining the `finally` function at the bottom to run code when a promise ends, we use the `finally` clause after the `catch` clause.

For example, we can write:

```javascript
const promise1 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(1), 2000);  
});  
const promise2 = new Promise((resolve, reject) => {  
  setTimeout(() => reject('error'), 1000);  
});

(async () => {  
  try {  
    const val1 = await promise1;  
    console.log(val1)  
    const val2 = await promise2;  
    console.log(val2)  
  } catch (error) {  
    console.log(error)  
  } finally {  
    console.log('finally runs');  
  }})()
```

In the code above, we got the resolved value of the promise assigned to a variable instead of getting the value in the callback of the `then` function, like in the `const response = await promise1` line above. Also, we used the `try...catch...finally` blocks to catch the errors of rejected promises and the `finally` clause instead of the `finally` function with a callback passed in to create code that runs no matter what happens to the promises.

Like any other function that uses promises, `async` functions always return promises and cannot return anything else. In the example above, we showed that we can chain promises in a much shorter way than with the `then` function with callbacks passed in as an argument.

* * *

Conclusion
==========

With promises, we can write asynchronous code with ease. Promises are objects that represent a process that runs for an indeterminate amount of time and may result in success or failure. To create promises in JavaScript, we use a `Promise` object that’s a constructor for creating promises.

The `Promise` constructor takes a function called the executor function that has the `resolve` and `reject` parameters. Both parameters are functions that we call to either fulfill the promise (which means end it successfully with some value) or to reject the promise (which means returning some error value and marking the promise as failed). The function’s return value is ignored. Therefore, promises can’t return anything other than promises.

Promises are chainable since promises return promises. The `then` function of promises can throw an error, return resolved values, or return other promises that are pending, fulfilled, or rejected.