Illustrated JS: Promises
Tags: codenewbie, javascript, beginners, learning
Published: 2020-08-11 19:46:42

_While learning JavaScript and programming in general, I find it useful to create some analogies to understand the concepts better. Here I will share an analogy about Promises in JavaScript. Feel free to contribute in the comments._

In Javascript, if we want to call a function only after an asynchronous function returns, we can use **callbacks**. Let's say I'm baking a cake with chocolate icing, in that case, my `bakeCake()` function is asynchronous and takes `prepareIcing()` (that's the callback) as an argument, calling it only when the cake is completely baked.

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/i/3ury9hcftllr91ye6h7k.jpg" alt="Drawing of a baker responsible for baking the cake, calling the one responsible for preparing the icing" width="50%"/>
  <figcaption>Fig.1 - The baker responsible for the baking cake action is **calling back** the function responsible for the icing preparation after the baking is finished</figcaption>
</figure>

But in this article we're focusing on using **Promises**. So how promises can help solve this problem? A promise is an object that wraps an asynchronous action and can be **fulfilled** with a value if the operation is successful or **rejected** with a reason, if it fails. This way I'm able to add a handler for a value (or a reason) that I will have only at some point in the future. 

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/i/rh1iefz5cshdhz0vpud6.jpg" alt="Drawing of a baker saying: Sounds complicated, right? Let's try again with a simple cake" width="65%"/>
  <figcaption>Fig.2 - My baker likes to use cakes to explain stuff</figcaption>
</figure>

Going back to the baking example, I can say my oven is a _promise of a cake_, because it wraps my baking cake action and starts with a _pending_ state (it's still baking). But I have a smart oven that will tell me when the action finishes. If the baking was successful, it's _fulfilled_ with a cake. Otherwise, it's _rejected_ with a burned cake or any other reason for the failure.

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/i/u88p9gsq2rz0i77ose50.jpg" alt="Drawing of an oven and the possible states for the cake promise" width="70%"/>
  <figcaption>Fig.3 - The oven is a promise of a cake that starts with a pending state and let's me know when it's fulfilled (success cake) or rejected (failure cake)</figcaption>
</figure>

Like we said before, using promises, we can add handlers for its possible states when it settles (it is either fulfilled or rejected). The `.then()` method can handle both success and failure (less common), and the `.catch()` method only can handle failure.

This is how I would handle a baking simple cake (no icing) action: if it is successful, **then** I can serve the cake. But if I burn my cake, I can **catch** the failed cake, throw it in the garbage and order a pie for my dessert instead. 😂 

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/i/m1b7e6p62im1mi5cc1ej.jpg" alt="Drawing of an oven and the possible states for the cake promise, including handler for success (serveCake()) and failure (orderPie())" width="80%"/>
  <figcaption>Fig.4 - If cakeBake() is fulfilled, **then** call the success handler, the serveCake() function. Otherwise, we **catch** the reason (burned cake) for the rejection and call the failure handler, the orderPie() function</figcaption>
</figure>

Another thing to keep in mind is that, since **one promise returns another promise**, they can be chained. In my previous cake with icing example, I can finish baking my cake, *then*  prepare the icing, *then* with both the cake and the icing ready, cover the cake. In that case, if any of the promises in the chain fails, I can handle all the rejections with only one *catch* and order a pie.

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/i/msussw6yh1hznczlydl7.jpg" alt="Drawing of chained promises and handlers for success and failure"/>
  <figcaption>Fig.5 - Promises chained with .then() and catch() to handle successes and failures</figcaption>
</figure>

But there's a better way to do what we did in the last example. My `bakeCake()` and my `prepareIcing()` functions are independent, which means they can happen at the same time. For that, we can use `Promise.all()` to wait for both results (cake and icing) before executing the `coverCake()` function.

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/i/4y4t4ee1dv0y2potjy6y.jpg" alt="Drawing of promise all example"/>
  <figcaption>Fig.6 - Promise.all() handles both the promise of the cake and the promise of the icing before covering the cake</figcaption>
</figure>

Inside `Promise.all()`, if _any of the promises_ rejects (fails), the entire promise is rejected. Which makes sense, right? I can't cover the cake if either the cake or the icing is missing.

This was a very simplified and summarised explanation of the concept of Promise, and the use of `.then()`, `.catch()` and `Promise.all()` methods. I hope it was clear enough.

_Thanks for reading, feel free to contribute in the comments. I promise my next article is already in the oven right now (pending). And eventually, I'll share it on [my twitter](https://twitter.com/facosta_marina) as soon as it's fulfilled or I'll post pictures of cats if it's rejected._

**Bullet points for this article:**

* Promises are objects wrapping asynchronous actions. 
* Promises start with a _pending_ state, and at some point in the future they settle to a _fulfilled_ (success) or _rejected_ (failure) state.
* A promise returns a new promise that can be used for chaining.
* We can add handlers to the success value or the failure reason once the action returns, by using `.then()` or `.catch()`.
* `Promise.all()` waits for all the promises to be resolved. If any rejects, it's rejected.

---

References and recommended further reading

* [Illustrated JS: JavaScript asynchronous behaviour](https://dev.to/marinafroes/illustrated-js-javascript-asynchronous-behaviour-1akc)
* [Asynchronous programing](https://eloquentjavascript.net/11_async.html) in Eloquent JavaScript by Marijn Haverbeke
* [Using promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises) in MDN Web Docs