JS Promises

How to handle Async code in JS

Promises

Promises in JS are a way for us to deal with asynchronous requests inside of our applications while still maintaining total control over what it is we're doing.


What does a Promise look like?

const getEvenRandomNumberBetweenTwoAndTen = new Promise((resolve, reject) => {
  const randomNumber = Math.floor(Math.random * 10 + 1)
  const isEven = number => number % 2 === 0

  isEven(randomNumber)
    ? resolve(`Your random even number is ${randomNumber}`)
    : reject(`Number returned was odd.`)
})

getEvenRandomNumberBetweenTwoAndTen
  .then(res => console.log(res))
  .catch(err => console.error(err))

In this example we are going to create a random number and check to see whether or not it is even. We are then either going to successfully print the random even number or error indicating the number was odd.


Why use Promises?

It may seem like there is an easier way to accomplish the previous example. That is true. We could replace the behavior with an if/else block and achieve the same goal in this case. The difference is that by using a Promise we made this process Asynchronous (non-blocking). Since the previous example is not very memory intensive, we probably wouldn't see much performance difference by not using a Promise. But let's think of a scenario that we would want the Promise there.

What if, in the future, we want to make this random number generator more complex. Maybe we're genearating a number based on a group of users XP, or how many times a given word appears in a body of text, or maybe maybe we need to query multiple APIs for values before generating this number.

This is now more memory intensive and we probably don't want to pause our application while this data is compiled.


Sync (Blocking) vs. Async (Non-Blocking)

Synchronous requests are the type of requests we are used to using so far. Your browser executes your JS code line after line, top to bottom. We don't start one process until we finish the previous. This is referred to as blocking as one process "blocks" all other processes from running. In most cases, this is fine, in fact, preferred.

Asynchronous code is non-blocking. This means that you can begin a process, let it run in the background, and let it notify you once it has a response from said request. This way you can continue to run other processes that may be unrelated, or at least don't need the data you're working on getting immediately to perform.


.then()

Promises have two built in methods that we are going to talk about. These methods handle the very important job of piping. Piping data is a term used to describe the passing of some piece of data to another function or handler. These handlers are responsible for mutating this data somehow and passing it on to the next handler.

So, in our case, when we get a positive response from our promise, we pass that value on to a .then() method and do something with it. If, on the other hand, we get a reject instead of a resolve then...


.catch()

Then we use .catch(). This is essentially a fail-safe. So if ANYTHING breaks while we're requesting information, waiting for a response, or processing the response, we receive some useful information as to what the problem actually is. This .catch() method is going to receive any errors that occur in this whole process and allow you to do something with them.


An Example

Let's take a look at the following example and examine the code in our browsers devtools (Open the script tag in elements).


Conclusion

So, Promises allow us to make asynchronous code, which is really beneficial for us in JS. It allows us to execute more concurrent processes which allows us to make more robust applications. This is how we build web applications that function the way that native applications do.