Javascript Promise 101
Tags: javascript, promise, async, then
Published: 2019-12-14 16:01:21

---
title: Javascript Promise 101
published: true
description: I promise it is not as hard as you think
tags: javascript, promise, async, then
canonical_url: https://irian.to/blogs/javascript-promise-101
---

Knowing how `Promise` works in javascript will boost your development skill exponentially. Here I will share:

1. The basic of `Promise`
2. How to use `then` 
3. `catch` and error handling

I promise you this will not be as hard as you think! 🤓

# What is a `Promise`?

Per [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
):

> The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.

In beginner's term, a Promise a JS object. It doesn't have a value the moment it is declared, but it will at some time *in the future*. This value is either resolved or rejected.

Suppose you ordered a new [hoodie](https://shop.dev.to/products/unisex-dev-hoodie) from dev.to. When you purchased it, it is technically yours, but it's not quite yours because you don't have it physically, just a promise that it will be delivered. At any moment, the hoodie's status is either: arrived, on delivery, or lost. *Note that even when the hoodie arrived, you may decide to reject it if it is not the right size/ you got a different product instead.*

Just like the hoodie, Promise has 3 states at any time: fulfilled, rejected, pending.


# Using `new Promise`

Let's get started using promise!

```
let foo = new Promise((resolve, reject) => {resolve('foo')})
foo.then(value => console.log(value) // foo
```

We can "shorthand" it by using `Promise.resolve`. Below is equivalent to above:

```
let foo = Promise.resolve('foo')
foo.then(value => console.log(value)) // foo
```

# Promise + setTimeout

Let's add timeout to mimic async:

```
let promise1 = new Promise((resolve, reject) => {
  setTimeout(function() {
    resolve('foo');
  }, 2000)
})
promise1.then(val => console.log(val)) 
console.log("I promise I'll be first!")
// I promise I'll be first!
// ... 2 secs later  ¯\_(ツ)_/¯
// foo
```

Note the order of logs.

Some notes:
1. Once promise is declared (`new Promise(...)`), time starts ticking. 
2. `promise1` itself is a promise object. You can see it on console: `promise1 // Promise {<resolved>: "foo"}`
3. You can access "foo" using `then` (or other async methods, but that's another article). My point is, you can't just `console.log(promise1)` in global scope and expect to access string "foo". You need to put `console.log()` inside `then`.

# Continuous chaining

Promise can be chained, allowing you to make serial promises.

```
let hello1 = new Promise(resolve => resolve("hello1"))

hello1.then(val1 => {
  console.log(val1);
  return "hello2"
}).then(val2 => {
  console.log(val2);
  return "hello3"
}).then(val3 => {
  console.log(val3)
})
// hello1
// hello2
// hello3
``` 
Here you'll notice that after my hello1's `then`, I `return` "hello2". This "hello2" is the value of val2. The same with the second `then`, it returns "hello3" and it is the value of val3. Note that to pass on argument in promise chain, the previous `then` must have a return value. If you don't return value, the next then will have no argument.

Here is what I mean:

```
hello1.then(val1 => {
  console.log(val1);
  return "hello2"
}).then(val2 => {
  console.log(val2); // no return
}).then(val3 => { 
  console.log(val3); // val3 is undefined
})
// hello1, hello2, undefined
```

Chain continues, but val3 has no value because the previous chain fails to provide return value.

# API call

I will only briefly touch making API call with Promise because the concept is the similar with `setTimeout`. Let's use [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API#Concepts_and_usage) because it is built-in (and you can play with it on chrome console!). This code from [typicode site](https://jsonplaceholder.typicode.com/):

```
let fetchTodo = fetch('https://jsonplaceholder.typicode.com/todos/1')

fetchTodo // Promise {<pending>}

fetchTodo
  .then(response => response.json())
  .then(json => console.log(json))
```
When we first make API call with `fetchTodo = fetch('https://jsonplaceholder.typicode.com/todos/1')`, it returns a Promise. 

We now how to deal with promise object - just `then` it!

# Catching Error and Rejection Handling

Remember the 2nd argument of new Promise? Suppose we don't like the result of our async operation. Instead of resolving it, we can reject it.

```
let fooReject = new Promise((resolve, reject) => {reject('foo rejected')})
fooReject // Promise {<rejected>: "error foo"}
```

It is really good habit to catch errors in promise. As a rule of thumb 👍:

> Every time we use `then` from now on, *always*, **always** have a `catch`

```
let foo = new Promise((resolve, reject) => {reject('error foo')})
foo.then(value => console.log(value)).catch(err => console.log(err)) //gotta catch 'em all!
foo //error foo
```

What just happened?

Let's compare it if we had only put `then` without `catch`

```
foo = new Promise((resolve, reject) => {reject('error foo')})
foo.then(val => console.log(val))
// Promise {<rejected>: "error foo"}

```
Ah, on my chrome console, it is complaining because an error is *uncaught*. We need to catch the error. Let's catch it!

```
foo.then(val => console.log(val)).catch(err => console.log(err)) // error foo
```

Now we see a cleaner log!

# Different rejection method 

You may ask, "hey man, what if I have a chain:"

```
let promise1 = new Promise(fetchSomeApi);
promise
  .then(processApi)
  .then(fetchApi2)
  .then(processApi2)
  .catch(handleCommonError)
```

"and I want to do something different for `processApi` and let handleCommonError to handle the remaining errors?"

Luckily there is more than one way to catch error! `then` takes second argument.

Recall our first code above: `let foo = new Promise((resolve, reject) => {resolve('foo')})`. We will use `reject` for custom error handling.

You can do something like this:

```
promise
  .then(processApi)
  .then(fetchApi2, customErrorHandling)
  .then(processApi2)
  .catch(handleCommonError)
```

Should something go wrong during `processApi`, the result will go to `.then(fetchApi2, CustomErrorHandling)` line. When `then` sees that it sees an error/ reject, instead of firing `fetchApi2`, it fires `customErrorHandling`. 

It is a good practice to still have `catch` even if you have reject callback.

# More resolve, reject, catch examples

Resolved example:

```
let successFoo = new Promise((resolve, reject) => {resolve('foo')})
  .then(val => console.log(`I am resolved ${val}`), err => console.log(`I am rejected ${err}`))
  .catch(err => console.log("HELLO ERROR"))
// I am resolved foo
```

Rejected example:

```
let rejectFoo = new Promise((resolve, reject) => {reject('error foo')})
  .then(val => console.log(`I am resolved ${val}`), err => console.log(`I am rejected ${err}`))
  .catch(err => console.log("HELLO ERROR"))
// I am rejected error foo
```

Note that it never reach `catch`. The second argument handles this. If you want to reach catch, jus don't pass 2nd argument:

```
let catchFoo = new Promise((resolve, reject) => {reject('error foo')})
  .then(val => console.log(`I am resolved ${val}`)).catch(err => console.log("HELLO ERROR"))
// HELLO ERROR
```

And that's all folks! Clearly not everything is covered but the basic cases. My goal is not to make you Promise gurus, but good enough to get you started so you can do more fancy stuff. Hopefully it all makes sense!

There are more into Promise that is not mentioned, I would suggest looking up [`all()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all), [`finally()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally), and [`race()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race). I *promise* (😎), it's worth your time!

Thanks for reading, as always, please  feel free let me know if you see an error/ typo/ mistakes. 

Happy hacking!

# Resources/ more readings
- [Promise docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
- [Master the JavaScript Interview: What is a Promise?](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-promise-27fc71e77261)
- [JavaScript Promises: an Introduction](https://developers.google.com/web/fundamentals/primers/promises)