JavaScript Promises. Part 2 — Fundamentals

Abdu Manaz C A
Nerd For Tech
Published in
6 min readMar 31, 2021

In part 1 of this series, we have understood why Promises were introduced. We know that the Promise API was introduced as a better paradigm to handle Asynchronous JS. Here we will understand What are promises and How to create promises with a simple example and we will, later on, look at a more practical example.

So what is a promise?

Imagine one morning at work, your colleague calls you up and asks you to do a favor. He needs you to go to the office parking lot and check whether there is an open spot. Since the parking space is limited, if no space is available he need not waste time and could park somewhere else.

You PROMISE you would do that.

You go to the parking lot to check for an open spot.

What are the different scenarios that could play out?

There is either an open spot or not. You call your colleague and let him know.

In any case, your promise has been fulfilled.

Is there another scenario? Imagine the lift is broken when you are on your way to the parking lot. And your office is on the topmost floor of the building. If you are like me, then you have no problem going down the stairs, but coming back up… that's a whole another thing. So you call back your colleague and let him know that you couldn’t actually check for an open parking spot since the lift was broken.

In this case, your promise to your colleague has failed.

Although very crude, this is what promises are in a nutshell.

Now let's get into the technical side of things using the above example.

As per MDN:

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

We have already touched upon Asynchronous functions. And you know that an asynchronous function will be queued and eventually executed(completed). Once your asynchronous function is completed it will return with a result, if any. This is what a promise object represents.

What does it mean in the context of our example?

Here, the Promise object refers to the actual promise that you have made to your colleague to check for an open parking space.

The task of you going to the parking lot, checking for an open space, calling back your colleague letting him know about the spot availability can be considered an Asynchronous operation. The resulting value can be either true/false based on the availability of the space.

How would it look like in code? Let's take a look

Let's break it down

You can create a Promise object using the new keyword.

The function passed to the constructor is called executor.
When a new Promise is created, the executor runs automatically. It contains the code which should eventually produce the result. In our case, going to the parking lot and checking for an open space.

We have wrapped the executor inside a setTimout function so that it is executed asynchronously.

Executor has 2 parameters resolve and reject respectively. They are callbacks and will be executed once our executor function has a result. As per our example: once you understand that whether a spot is available/not.

Based on the availability of the parking space, you call resolve(true) or resolve(false). This means, you have gone to the parking lot and returned with a result. You have fulfilled your promise.

But as we have discussed, there is a 3rd option where your promise might have failed. Let's take a look at the code for that

In this case, you are not returning with a result. Instead, you are throwing an error. So, your promise is rejected.

The promise object returned by calling the new Promise constructor has 2 internal properties:

  1. state: Initially the state is pending. Based on which callback is invoked, either resolve/reject, the state will change to fulfilled/rejected respectively.
  2. result: The value that is passed on to the callback. In our case, true/false.

It’s important to note that a promise can only resolve or reject

Also any state change is final and all further calls of resolve and reject are ignored.

This means, If we omit the return statement in the above example, the executor will execute until the last statement, (i.e. either resolve(true) or resolve(false)). But irrespective of that, the state of the promise will still be rejected and result will be the Error object created.

Alright, we have learned to create a promise. We know that the promise object represents the value returned by the eventual completion of our asynchronous operation (copy-pasted from above ;) ). But how can that value be consumed?

In our example, the consumer is our colleague, who asked us to perform this whole task. How will he be able to consume the promise once it is fulfilled/rejected?

To create a consumer, we use the then/catch/finally methods.

The syntax of thenis as follows:

then method has 2 arguments. Both are functions.

The first function runs when the promise is resolved.
The second function runs when the promise is rejected.
result/error will be the value returned from the promise.

catch method has only 1 argument, which will be executed if the promise is rejected.

Confusing? Let’s take a look at how our consumer function will be written.

As we can see, we have applied methods then and catch to the promise object (previous example).

Once the executor finishes and resolves/rejects with a value, based on the callback invoked, either then or catch will be executed.

If we could check for the parking spot, promise will be resolved with either true/false. In that case, the first function in then method will be executed.

If the lift was broken, promise will be rejected and an error object returned. In that case, the function in catch method will be executed.

You could also completely omit the catch block and handle both cases using then method itself. Which would look like this

Whether to use a catch block, or handle the error in then block, depends on our requirements and whether the promises are chained together. We will be diving into Promise chaining in the next section. For now, just remember that it is possible to handle the error in then block itself.

Now, let’s finish with a Practical Example

fetch API allows us to make network requests. The response from fetch() will be a promise with value being the response sent from the server.

If we get a valid response from the server, function in then method will be executed and if the server responds with an error, the function in catch method will be executed.

Promise is a powerful API and I hope you got a basic understanding of it.There is much to be covered, like Promise chaining and different methods like Promise.all(), Promise.any() which we will see in the upcoming parts.

Click here to go to the next part where we understand Promise chaining.

If you have found this article helpful, make sure to clap and share it with your friends. Make sure to follow me as I Promise to provide more simplified explanations ;)

--

--