The Story Behind JavaScript Promises - A Use Case Based Approach!
Tags: javascript, frontend, webdev, tutorial
Published: 2021-08-07 16:35:44

## Table Of Contents:
- [❓ Why should you read this?](#Why should you read this?)
- [🏇 In a hurry?](#In a hurry?)
- [🤝 How Promises Are Made: Please Put A Ticket!](#How Promises Are Made: Please Put A Ticket!)
- [🔛 Main Usages Of A Promise: Making API Calls.](#Main Usages Of A Promise: Making API Calls.)
- [✅❌ Callbacks: The Green And The Red Button.](#Callbacks: The Green And The Red Button.)
- [↩️↪️ Callbacks: Then & Catch.](#Callbacks: Then & Catch.)
- [⛓️ The Methodology Behind Promises: Returning Objects!](#The Methodology Behind Promises: Returning Objects!)
- [🕸️ Static Methods: `Promise.all` & `Promise.allSettled`](#Static Methods: `Promise.all` & `Promise.allSettled`)
- [🏃🏻‍♂️ Static Methods: `Promise.any` & `Promise.race`.](#Static Methods: `Promise.any` & `Promise.race`.)
- [🔚 Promise Callbacks: `finally`.](#Promise Callbacks: `finally`.)

***
The young librarian felt satisfied with what she did. Sarah had started her job when she was only 22 years old. Having known her as a long-time member of the library, the kind Mrs. Perkins hired her. 

Mrs. Perkins had been the library's manager for as long as 30 years.

Now Sarah was the main person responsible for the place. She did a great job. People liked how she treated them and controlled everything.

But it didn't take long before things got out of control. 

Mrs. Perkins retired. The girl had to do everything alone. And a new wave of readers was joining the library. She couldn't deliver services anymore. 

She was forced to make **promises**...
***
## ❓ Why should you read this?<a name="Why should you read this?"></a>
This might seem a long article. And the story might look unrelated. 

But let's face the truth. How many times have you learned a concept but have never used it? 
Perhaps there were situations where you could use `Promise.race`. But you didn't. Because despite you knew what it did, you weren't sure what its use case could be. 

And when you got into a problem which you could solve using `Promice.race`, you chose to go your own way. Because you weren't even sure if it was useful there.

You knew what it did. But you didn't know its use case.

Here, I'm presenting you with a story. It also teaches you about different ways you can use `Promises`. 

But it also tries to symbolize its use cases through a real-world story. Next time you face a similar situation you'll be quick to know how to handle it. And if not, you have at least read a story!😉

Enough talk. I have promises to keep.
***
It started with the Covid-19 pandemic outbreak. Everyone wanted to pass their quarantine by reading books. But no one could go to the library due to the health restrictions. They had to keep social distance. 

Then Sarah came up with the idea to make an online deliverance system. Anyone could use the library's website to reserve books.

She thought that she could deliver the books on her bike to their door front. And as the transportation cost her time and money, she took a very small amount of dollars for her service.
But she wasn't always online and couldn't plan every books' deliverance on time. She had to deliver them herself and close the library since no one took her place.

She needed extra help. Somehow.
***
## 🏇 In a hurry?<a name="In a hurry?"></a>
I have separated everything into different parts. Each of them is about a specific side of the `Promises`. So you can skip any part you are confident about. 

Already know how to make `JavaScript Promises`? Skip the introduction part!
***
She called her cousin and asked him if he could design an ordering system for the library's website. She described the process as: "People will have to log in to their accounts. And if there is a book they want to request, they should put an online order ticket for it."

But since it was not clear when she could deliver the books, the users had to wait for the website to notify them.
It sent a message. If the book was available to deliver, it informed them she had **resolved** the ticket. Otherwise, it contained a **rejection** message.

She named it the **Promise System**. Likewise the `JavaScript API` we're going to learn about.

Let's dive in!
***
## 🤝 How Promises Are Made: Please Put A Ticket!<a name="How Promises Are Made: Please Put A Ticket!"></a>
To create a `JavaScript Promise` you can use the `new` keyword:
```js
const thePromise = new Promise()
```
The `Promise Object Constructor` accepts a `function` as an argument. This function runs the process that we're going to promise its fulfillment. 

In our story, the way Sarah manages the ordering through tickets resembles such a `Promise`. Either it is `fulfilled` with the book's delivery or `rejected` for a reason. 

This function can in turn accept two arguments: `resolve` and `reject`.
Both of which are callback functions that we can delegate on certain points. 

We use `resolve` as a fulfillment signal and pass it the final data. By calling `reject` we make clear that the `Promise` has failed.

From what we've learned we can construct a `Promise` by writing the following lines:
```js
const theOrderingProcess = (resolve, reject) => {
  // The process with the unknown duration.
  // Function body goes here.

  // If anywhere in your code, 
  // you think your promise is fulfilled, 
  // (e.g. Sarah finds an ordered book is available),
  // you can call resolve and pass it 
  // the data you would like to return. 
  // Like the following:
  // resolve(theBookData)

  // But if somehow the promise has failed to fulfill, 
  // (e.g. A book is currently borrowed),
  // you can call reject and
  // pass it the reason to rejection:
  // reject(theRejectionReason)
}
const theWebsitePromise = new Promise(theOrdeingProcess)
```
***
Every time someone put a ticket for a book, he/she had to wait for a certain process to come to an end.
It was not as if you selected a book and immediately had it on way to your home. Things took time. How long? No one knew for granted.

Mrs. Perkins wasn't an all-up-to-date lady. So she had stored most of the data about the existing books and the borrowed ones in an old Access database. It took time to transfer them to a server. And Sarah wanted things to get done as soon as possible.

She had to use the Access database. By herself.
***
## 🔛 Main Usages Of A Promise: Making API Calls.<a name="Main Usages Of A Promise: Making API Calls"></a>
Nowadays most websites use a database on their back end side. Like how Mrs. Perkins stored the library's data in an Access database. 

Of course the website databases use automations!

A web application's front end needs to send a request to a server endpoint to receive some data. Then using this data the application can deliver its services.

As the front end sends the `request`, the process mounts into a pending status. It will stay in this status until it either receives a response from the back end or receives none.

The pending status could take for an unknown period. This depends on the networking conditions of the user and the server, and how fast they can transfer data. Additionally, the back end itself might need to process some data and take extra time.

An example of sending a `request` using the `JavaScript Fetch API` looks like the following:
```js
const theRequest = fetch("https://example.com/endpoint")
```
The fetch method constructs a `Promise Object`, and returns it. So we can use its returned value same as a simple `Promise Object`. Helping us to get rid of creating our own `Promisess`.

Want more comfort? Use axios.
***
The library's online ordering system took tickets from its users. They contained information about the user and the selected book. Sarah reviewed the tickets. And checked for the books' availability in the Access database.

If everything was okay, a green button labeled as `resolve`, awaited Sarah's click. Otherwise, the big red button was ready to delegate a `rejection event`.

No one knows for sure. But rumors are there was a black button too. For dark purposes. Unknown.
***
## ✅❌ Callbacks: The Green And The Red Button.<a name="Callbacks: The Green And The Red Button"></a>
We call the processes like the API requests `Asynchronous Operations`. They vary from the `Synchronous` ones which are simple `Program Expressions`. 
A `Synchronous Operation` takes a constant time to complete. The system runs them in a sequence. It waits until the execution of one is complete before it runs the next.

A `Synchronous Operation` looks like the following:
```js
const x = 10;
const z = function(num1, num2) {
  return num1 + num2;
}
const sum = z(x, 20);
```
Every line of this operation is predictable. The compiler will be executing each line one after another. There's nothing unpredictable that could block the program's main thread from running.

But an `Asynchronous Operation` can block the program's execution. This is so because its fulfillment depends on the network conditions and speed. Even if the user owned a fast network, the back-end servers could be facing trouble. This can result in no response or a longer-running process.

How can we write an `Asynchronous Operation` and make sure that it doesn't block the rest of the code from running?

The answer is: "by using `Callbacks`".

Of course, while it sounds like a heartwarming name, wait until you are caught in a `callback hell`!
***
When the user put a ticket for a book, he registered for future events. He was awaiting a `response` to his `request`.

Either this response arrived, or some problem prevented it from ever coming.

Now the user was using a true `Promise System`. The library's website provided this system. But the user didn't have direct access to the promise. He was listening to it.

Then the user had to make his own plans based on this `Promise`. He was telling himself: if the reply was a successful message `then` I'm gonna return my last book. If not, `then` I can choose another one. Maybe the reply never came, or the website's server went down. This problem will `catch` his eyes, and so he was going to call the librarian and inform her. 

`console.warn('I never got a response!')`.
***
## ↩️↪️ Callbacks: Then & Catch.<a name="Callbacks: Then & Catch"></a>
If you use the `JavaScript Fetch API`, it will return a `Promise Object` by default. You don't have to write the `Promise` yourself. You have to listen to it. How?

Every `Promise` returns an `Object`. And this `Object` owns 2 important methods. `then` and `catch`. You can use these methods to attach `callbacks` to a `Promise`. You pass them a `function` which will be called as soon as the `Promise` delegates an `event`. What events?

You can call the `resolve` callback inside a `Promise Function`'s body and pass it what data you want. Then the `Promise` calls the `callback function` inside the first `then` call and passes the data to it. The `Promise` calls the `catch` method as soon as you call the `rejection` callback.

Let's visualize this process by an example:
```js
const request = fetch("https://example.com/endpoint")
request
  .then((data) => data.json())
  .catch((error) => console.log("Error in fetching the request", error))
```
* Here we call the `fetch function` and pass it the `endpoint URL`.
* The `fetch function` creates a `Promise Object` and returns it.
* We store this `Object` in the `request` variable.
* We call `request`'s `then` method and pass it a `function`. The function can receive as many arguments as it expects. It retrieves those arguments from what the `Promise` passes to the `resolve` callback. Then the given function can do as much as it desires with the given data.
* Next, we call `request`'s `catch` method. We pass it a function. And expect the `Promise` to call this function when it `rejects` or the `then` method `throws` an `Error`.

* In the end we run the code to see if it works. Of course it does. And if not, we won't hesitate to point our finger at the back end:)

A question exists. The `then` and `catch` methods only add callbacks to the `Promise Object`. So why aren't they `properties` to which we can attach the `callback functions`? Wouldn't it be simpler?

We'll find the answer.
***
Everything Sarah did resulted in a `Promise`. 
Hitting the `resolve` button was only the first step. 

She had to find the book in the library. She had to package it next to the other ones which she had to deliver the following day.

She had to mark each package with the right user's information. This included their names and addresses. She had to be careful when she loaded the packages on the bike. Not to disturb her ride.
 
She had to ride through streets and alleys. Dodging traffics and caring for her safety. Reaching her destination, she had to ring the doorbell. If the client was present, `then` she delivered the book.
And `then` she took the reader's previous book to return it to the library. 

After repeating the same routine for every client, she had to `finally` go back to the library. She placed the returned books on the shelves. `Then` filled the Access database with data about the returned and the delivered ones.

After all, it was time to review that day's orders and check for their availability. Then managing to hit the `resolve` or the `reject` buttons.

Even the rest she got by her night sleeps, was a promise she had made to her body.

And it feels good to fulfill promises. Doesn't it?😊
***
## ⛓️ The Methodology Behind Promises: Returning Objects!<a name="The Methodology Behind Promises: Returning Objects!"></a>
We've faced a question. A matter which insists that providing `callbacks` through methods is useless. The `Promise API` can instead provide special `Object Properties`. Or the ability to add an array of `callbacks`, for another instance.

But think of all the possibilities you might face while developing front-end applications. You won't always want the `callbacks` to run in order. You might not remember a case for this at the moment, but sure someday you'll face it. 

Different scenarios need different approaches. And if the `Promise` is going to be of any help during these situations, it has to be flexible.

Let's have a look at a piece of code:
```js
const aPromise = Promise.resolve("resolved")
aPromise.then(res => console.log(res))
```
Here we have been able to use the `Promise`'s static `resolve` method. Without even having to construct a new `Promise Instance` we were able to return a `Promise Object`.

Now we can call this `Object`'s `then` method. Or its `catch` one. 

Well, what good is that for? You may ask. To find the answer let's have a look at another example:
```js
const firstPromise = Promise.resolve({message: "hello"})

const secondPromise = firstPromise
  .then(data => JSON.stringify(data))
  .then(json => json.indexOf(message) !== -1)
  .then(boolean => {
    if(boolean) console.log("JSON string was created successfuly!")
    else throw new Error("JSON creation error")
  })
  .catch(error => console.error(error))

const thirdPromise = firstPromise
  .then(data => {
    if(data.message) return data.message + " world!";
    else throw new Error("The data doesn't contain a message!")
  })
  .then(newData => console.log(newData.toUpperCase()))
  .catch(error => console.error("Error in third Promise", error))
```
Here, we've initiated a `Promise Object` using only `Promise.resolve`. This promise object gives us all the superpowers we want. We can call its `then` method as much as we want, in a `chain` or in `separate calls`. This allows us to create various `waiters` for the same process. What is a `waiter`?

Let's say you have got to fetch data, which you will use in different parts of your application. But there's a problem. You can reuse `synchronous operation` data as in `variables`. But you can't do that with `asynchronous` data. You should wait for it to become available.

Now, there are different parts in your project, awaiting this data. We can refer to these parts as `waiters`. They're observing the `Promise`'s status and as soon it `settles`, they will read its data.

The above example showcases how the `then` and `catch` methods help you to reuse the same data in different scenarios.

This way the `Promise API` is providing an easy-to-use solution.

But it also provides us with some useful static methods. We can use them to handle different situations. They include: `Promise.all`, `Promise.allSettled`, `Promise.any`, and `Promise.race`.
***
Every day, to return to the library Sarah had to make sure that she had visited every one of her destinations. If all the clients were present at home, the book exchanges were successful. Otherwise, some of them failed.

She didn't need every deliverance to be `resolved`. She needed to have finished the process which was about going to the client's house.

In the end, she returned to the library. And when she was ready to enter the reports in the Access database, she would ask herself: "Was everyone at home? Did any of the orders remain undelivered?"

She classified the undelivered books in a separate database. And she sent the clients an Email that expressed the situation.

If she had delivered every book then, she only had to set that day's deliveries as done, in the database. Nothing further to take care of.
***
## 🕸️ Static Methods: `Promise.all` & `Promise.allSettled`<a name="Static Methods: `Promise.all` & `Promise.allSettled`"></a>
The `all` method accepts an array of `promises`. Then it waits for all the promises to `resolve`. If any of the promises `rejects`, it will immediately return with the rejection reason.

This function behaves like what Sarah asks herself every night: 'Was everyone at home? Did any of the orders remain undelivered?' 

She will know that she has done all her tasks once she delivered the last book. If so, only the clients' returned books would be on her bike. 

 `Promise.all` resolves once every `Promise` in the promises array passed to it resolves. It returns an array of what each promise had returned. Like the books that the library's clients returned.

Sarah immediately knew that the delivery has failed If none of the clients were present at home. She would return with the undelivered book still on her bike. 

If any of the promises you pass to `Promise.all` rejects, it will immediately reject. With the `rejection` reason of the rejected promise.

An example of `Promise.all` usage:
```js
Promise.all([client1, client2, client3])
  .then(returnedBooks => console.log(returnedBooks))
  .catch(rejectionReason => console.log("Error: a book was not delivered.", rejectionReason))
```

We said that Sarah's return to the library didn't depend on every client's presence. She needed to make the visit. So if she had toured around all the clients' addresses, she was ready to return to the library. And on her bike, she transported all the books. Whether returned or undelivered. 

For a likewise behavior with `JavaScript Promises`, we can use `Promise.allSettled`. 

Every `Promise` passes through two main states: `pending` and `settled`. The settled state is when the promise has been `fulfilled`. The settlement either happens with resolve or a rejection. 

The `all` method immediately returned when a `Promise` rejected or every promise resolved. 
But the `allSettled` method immediately returns. When all promises have either `resolved` or `rejected`. 

When they are `settled` indeed.

What the `allSettled` method returns in its `resolve`, consists of an array of objects. Each object has a `status` property which is either `fulfilled` or `rejected`. 

If the status is `fulfilled` then the object provides a `value` property too. Otherwise, it owns a `reason` property.

A demonstration of it in code:
```js
Promise.allSettled([client1, client2, client3])
  .then(books => 
    books.forEach(book => {
      if(book.status === "fulfilled") {
        console.log("A returned book", book.value)
      } else {
        console.log("An undelivered book", book.reason)
      }
    })
  )
```
***
Soon enough troubles showed up.

The website's users had to wait a long time for the response message's arrival. Then they started to see more rejection messages. No matter what book they ordered, a rejection message awaited them in their inboxes after 1 to 2 days.

Some of the users tried to contact Sarah through Emails. But they only got a simple reply.  It stated: "The requested book is currently borrowed by someone else. You can try to order it later, or borrow another one."

These replies worsened the situation. It surprised the clients that Sarah didn't even state when the book will be available. Or whether she could put them in a queue. 

Everything seemed unexpected and random.

Sarah at first didn't notice any issue. She was still taking books for some people. But later it caught her eyes that things were getting weird.

Before anything started to happen she wanted to find a solution to speed her routine up. She called her cousin and asked him if he could help her in searching the current Access databases. She needed to be quicker in finding out if a book was available.

He said he would look into it and call her as soon as he found anything. The next day he had a solution. He could write a `python bot` which would search every Access database. And to speed things up, he had found a useful algorithm for it too.

He made the bot ready within a day. It searched the Access files for a specified book name and stated whether it was available to borrow. His special algorithm indeed created several `asynchronous operations`. 

It searched each file in real-time with the others. As soon as any of the files contained a search result matching the book, the bot took it. Then it terminated all the search operations.

She had separated the Access files into two different directories. She named one of them the **library books** and the other the **ordered books**. 

Books in the ordered books' directory were currently ordered or delivered. 

The library books databases had a list of all books in the library. It also contained information on whether a book was available or not.

While developing his bot he had decided that the result was either in the `ordered books` databases or the `library` ones. If it was the ordered ones then it was obvious that the book wasn't available and Sarah had to reject the ticket. 
Else if it found the result in the library databases it was either available or not. 

This speed the search up because the ordered databases were smaller than the other group. So if it found a match result among them it terminated the searching quicker.

But two weeks after the new bot's implementation most of the orders had to be rejected. She had had a regular delivery count of 9 to 10 books per day. Now, this number had fallen to as low as 3.

Some days none at all.

Many of the borrowed books remained unreturned for a long time. Their owners didn't even order new ones.

And then she heard rumors. One of her best friends had tested positive for Covid-19. The infection statistics were surging in her town. She called some of her customers to ask why they weren't trying to return their books.

Her suspicions proved right. Covid-19 had hit many of her customers. But some other ones were actually bothered with the site's functionality. They hated waiting a long time for no results.

She tried to talk them back into using the library's website. She even promised that she will fix the issues. But **promises** weren't convincing anymore. 

One night she called her cousin. Tears in her eyes. "I failed.", she said. The confession feeling bitter. "I failed badly."
***
## 🏃🏻‍♂️ Static Methods: `Promise.any` & `Promise.race`.<a name="Static Methods: `Promise.any` & `Promise.race`"></a>
`Promise.any` accepts an array of promises. And resolves as soon as **any** of them `fulfills`.

The library's users chose a book and ordered it and waited to see if it was available. If not, they would go for the next one. But this process took a long time. They had to wait for each order's message to arrive before they could decide anything.

And when the system became unresponsive it wasted the users' precious time by days and weeks.

What if they could find a way to order many books together and get the first book that was available? Of course, it was impossible with the library website's architecture. Sarah wouldn't have allowed this. This could ruin all her plans.

But this is not the case with JavaScript. If you are waiting for the first promise that resolves, use `Promise.any`. It works the same way as the hack the library users wished for.

An implementation of `Promise.any`:
```js
Promise.any([order1, order2, order3])
  .then(order => console.log("this order resolved first", order))
  .catch(error => console.log(error)
    // expected output: "AggregateError: No Promise in Promise.any was resolved"
  )
```
As soon as any of the promises resolves, the `Promise Object` calls the callback passed to `then`. If all reject, it enters the `catch` territory.

Then there is `Promise.race`. It resolves with the first `Promise` that `settles`. In case you've already forgotten, a `Settled Promise` is either `fulfilled` or `rejected`.

Now, why should someone need to implement that? It's actually difficult to name a good use case for `Promise.race`. But still, there are few times when it could be of help.

Let's think about the bot that Sarah's cousin had developed. It exited the processes as soon as any of them returned anything. You might say that the bot's actual action is like what `Promise.any` does. It returns as one of them `fulfills`.

Then it can be a bad example. But let's say that the `Promise` which he used to search the `ordered books` didn't fulfill when it matched a book. Let's say Sarah's cousin was smarter and played a trick on it.

If the search in the ordered books matched a result then its `Promise` rejected. Otherwise, if it had searched the entire databases and found none it resolved. But, if the search process related to the library books found a match and it was available then it resolved. Otherwise, the `Promise` rejected.

So here we have got a bright point. The rejection of one of the promises means the resolving of the other one. And vice versa.

Now, `Promise.race` can help us in reducing the time we need to wait for a useful response.

Let's have a quick look:
```js
Promise.race([searchLibraryBooks, searchOrderedBooks])
  .then((book) => console.log("Book is available."))
  .catch((reason) => console.log("Book is not available, because ", reason))
```
The library books have an alphabetical sorting. The ordered ones are sorted by their order date. So it's possible that the search in the whole library books could make a quicker match sometimes.
***
It didn't take long before Sarah received a phone call from his cousin. He sounded anxious. And when she asked him what was wrong, he replied: "The bot had a bug, Sarah. There are always several versions of a book in the library. This means that if someone borrows one of its versions the book could still be available. I hadn't thought about this in my code. If one version of the book was ordered then I tagged it as unavailable. I'm sorry Sarah."

Sarah was in shock for several seconds. How didn't this even cross her own mind?
"Can you fix it?", she asked.
"Well I'll do my best.", the other replied.
"Then you better do it.", she couldn't control how loud her voice got. "And do it as soon as possible!"

It took another day for them to fix the issue. She sent Emails to her clients. Informing that they have fixed the issue. And the users could start using the website immediately.
***
## 🔚 Promise Callbacks: `finally`.<a name="Promise Callbacks: `finally`"></a>
We learned about `then` and `catch`. But the `Promise Object` also provides us with another method. It doesn't care if the `Promise` fulfills or not. It only cares that it `settles`. And any `then` and `catch` calls have already been delegated. Then it runs and does what you ask it for.

An example:
```js
const websiteDelivery = Promise.resolve({useServerDatabase: false})
websiteDelivery.then(condition => {
    if(!condition.useServerDatabase) console.log('Use Access database')
    else throw new Error('Data isn't still moved to the server')
  )
  .catch(error => console.log("Error in starting delivery website", error))
  .finally(_ => console.log("No matter if you lost 100 times. Try for the 101st time!")
```
The `Promise Object` calls the function you passed to the `finally` method in any condition. After the `Promise` settles.
***
"The devil is always in the details." This was what Mrs. Perkins told Sarah after she heard her story. She went on: "You saw the big picture. You wanted to start a movement and to modernize our town's library. But you forgot the details my dear. You told yourself that you can handle the database work. But this was something you had to leave to the programmer. After you've finally restored the library's daily life, I hope you've learned something. And I hope that this damned pandemic ends very soon."

Sarah hoped too. And she smiled.
***
It was a long read. And a longer one to write. I think it was worth the time.

The hardest part was about `Promise.race`. I could hardly find a good use case for it. And I hope the idea I came up with could help you make a picture of it.

Do you think there are better use cases for any of these methods? Or do you think I have gotten something wrong? 

Please let me know in the comments. Writing this article helped me a lot in understanding the concepts myself. Your comments can help me and the others further too.

Thanks for the reading.

The cover image is by [Epic Top 10 Site](http://www.epictop10.com/).