JavaScript Promise Complete Tutorial

In this section, we will learn what the Promise is and how to use it in JavaScript.

What is Promise in JavaScript?

In the process of developing a JavaScript program, there are cases when we need to communicate with an external program on the same or another computer.

For example, our program might want to request a server for a file. Now, while the target server is preparing the file to send it back, we want our program to continue to work on other tasks. This process is called `asynchronous`.

Essentially, when two programs work at the same time, without making one to wait for the result of the other, this is called asynchronous execution.

Note: the opposite of asynchronous is `synchronous` where the order of execution is sequential. And basically one program waits for the response of another one and then proceeds to run the rest of instructions.

Now the question is how our program can get the result of a request to an external resource asynchronously?

This is where the promise comes in:

A promise is an object representing an asynchronous result. We use promise to observe the result of an asynchronous process, and/or give the promise to other code so that other code can observe that result.

Promises are JavaScript’s version of a pattern variously called `promises`, `futures`, or `deferred`.

You should know that a promise doesn’t do anything of its own and it’s just a way to observe the result of something asynchronous.

Promises don’t make operations asynchronous.

They just provide a means of observing the completion of operations that are already asynchronous.

To use promises in an asynchronous operation, there are two tasks that need to be done:

  1. First, we need to define a promise object.
  2. Defining the handlers for the promise object.

How to Create Promise in JavaScript?

There are three ways in which we can create a Promise object:

JavaScript Promise Constructor:

The `Promise` is a constructor function that can be used to create a promise object from.

Syntax:

Promise(executor-function);

The constructor takes one argument and that is a reference to a function. This function has a fancy name which is known as the `executor function`. The reason that we call it the `executor-function` is because inside this function we define the asynchronous operation that we want the promise object to handle its result. For example, if we want to get an external resource, we put the instructions for this async operation inside this function.

The Promise object calls this `executor-function` and passes two reference functions as its arguments.

  • The first function is called `resolve` and inside the executor function, we call it if the result of the async operation is successful.
  • The second function is called `reject` and it is called only if the result of the async operation is failed.

After preparing the Promise object, we can use that object to define the handlers.

Handlers are basically the blocks of code that should be executed if the async operation is failed or successful.

For example, we sent a request to an external server for a file. Now two cases might occur:

  • The operation is successful and we got the files. So now what’s the task that should be executed in a successful request?
  • The operation failed. So what should be done now?

Typically, we create at least two handlers for each Promise object.

  • The first handler is for when the `resolve` function is called (When the operation was successful). Basically, when the `resolve` function is called, the body of this handler will be run.
  • The second handler is for when the `reject` function is called (When the operation failed). This handler will be run when the `reject` function inside the executor-function is called.

Alright, before you get into more details, let’s run an example first:

Example: creating a Promise via the Constructor in JavaScript

function exe(resolve, reject){
  setTimeout(()=>{
    const res = Math.random()>0.45; 
    if (res){
      console.log(`The value is less than 0.45`);
      resolve(res);
    }else{
      console.log("The value is over 0.45"); 
      reject("Failed");
    }
  },5000); 
}

const prom = new Promise(exe);

prom.then(value=>{
  console.log("Resolved handler");
  console.log(value);
},
failed=>{
  console.log("Failed handler");
  console.log(failed);
});

Output:

The value is less than 0.45

Resolved handler

true

This program has 3 parts:

1- Creating the promise object:

We’ve created the Promise object via the `Promise` constructor function in the statement:

const prom = new Promise(exe);

Note: the executor-function `exe` is passed as the reference function to the `Promise` object and will be called by this object.

2- Defining the body of the `executor-function` and resolving or rejecting the promise object:

Inside the body of the `exe` function, we’ve used the `setTimeout` function and the reference function that we passed to this timer will be executed after 5 seconds.

Note: if you’re not familiar with the `setTimeout` function, please check the related section.

When the body of the function ran after 5 seconds, there’s one statement that defines whether the `resolve` function should be called or the `reject` function.

This is the statement:

const res = Math.random()>0.45;

The `Math` is an object that has multiple useful methods for mathematical operations, including the `random()` method. When we call this method, it will produce a random value in the range from 0 to 1.

So here we called the method and compare the result with the value 0.45. If the result is `true` then the body of the `if` statement will run, otherwise the body of the `else` statement is the one to run.

In the body of the `if` statement we called the `resolve` function with the value of the identifier `res` and in the body of the `else` statement we’ve called the `reject` function with the value `failed`. So now, depending on the result of the `random()` method, one of these two functions will be called.

3- Using the promise object to create the handlers for the `resolve` and `reject` functions:

As mentioned before, there should be instructions to be run when either `resolve` or `reject` function is called.

A promise object has 3 methods to register the handlers:

1- JavaScript Promise then() Method

We use this method to add a resolved handler as well as a rejection handler.

The `then()` method gets two handlers (two functions) and, depending on how the target promise is settled (resolved or rejected), one of the two handlers of the `then` method will be invoked.

Note: this method mainly used for resolving, however.

Promise then() Method Syntax:

We will talk more about the `then` method in the next section, but in short it takes two functions:

  • The first function will be called if the target Promise object resolved.
  • The second function will be called if the target Promise object rejected.

Example: using Promise then() method in JavaScript

In our example, if the promise resolved (successful), then the message `Resolved handler` and the value `true` will appear on the console. This is because the body of the resolved handler in the `then` method has these two statements:

console.log("Resolved handler");

console.log(value);

On the other hand, if the target-promise gets rejected, then the message ` Failed handler` and `Failed` will appear on the console. This is because the reject handler in the `then` method has these two statements:

console.log("Failed handler");

console.log(failed);

Note:

  • In the executor-function the argument that we pass to the `resolve` and `reject` functions will be passed to their handlers.

2- JavaScript Promise catch() Method

Via this method, we can add a rejection handler to be called when the target promise gets rejected.

Note: this method is covered in the JavaScript catch() section.

3- JavaScript Promise finally() Method

Via this method we can add a finally handler to be called when the promise gets settled, regardless of how.

Note: this method is covered in the JavaScript finally() section.

JavaScript Promise States:

You should know that a Promise has states. These states are:

  • Promise Pending:
  • Promise Resolved (Promise Fulfilled to Resolve)
  • Promise Rejected (Promise Fulfilled to Rejection)

A promise starts out pending and then can only be settled (fulfilled or rejected) once. A settled promise can’t go back to being pending. A fulfilled promise can’t change to a rejected one or vice versa. Once settled, the promise’s state never changes.

JavaScript Promise Pending

When we first create a promise object and is not settled yet, which means neither `resolve` nor `reject` function is called; the promise is in the state of pending.

JavaScript Promise Resolved

Promise Resolved(AKA fulfilled): If the promise has been settled with a value without any error, the state of promise will change to `resolved`. A promise gets resolved when a call to the `resolve` function occurs.

JavaScript Promise Rejected

When the promise has been settled with a rejection reason; this means a call to the `reject` function has been occurred and the promise is considered as a failed.

Calling a Promise within Anther Promise in JavaScript

So far we know that if we call the `resolve` function in the executor-function, the resolved handler of the target promise-object will be run. If we call the `resolve` with another promise, the promise gets resolve to that other promise (it will get fulfilled or rejected depending on what happens to the other promise).

Example: calling another promise within the body of another promise in JavaScript

function exe(resolve, reject){
  resolve(new Promise((resolve, reject)=>{
    reject("The second promise failed");
  })) ;
}

const prom = new Promise(exe);

prom.then(value=>{
  console.log("Resolved handler");
  console.log(value);
},
failed=>{
  console.log("Failed handler");
  console.log(failed);
});

Output:

Failed handler

The second promise failed

As you can see, inside the body of the executor-function of the first promise we called the `resolve` function. But the argument of this function is itself another Promise object.

So the result of this second Promise, defines if the `rejection` handler of the first promise should be called or the resolved handler.

Now, because the final result of the second Promise is failed (in the second promise, the reject function is called), the rejection handler of the first promise gets called instead!

Again: calling the `resolve` function of a promise won’t cause the call to the `resolve-handler` of that promise if we passed another promise object to the `resolve` function. Basically, this second promise defines which handler of the first promise should be called.

JavaScript Promise rejection method and another Promise as the Argument

The situation you saw in the last example is not true for the `reject` function! Basically, if we call the `reject` function and pass a promise as its argument, it will use that promise as the reason of rejection (this means the `reject` handler of the first promise will be called anyway, even if the second promise fulfilled successfully).

Example: using another Promise object as the argument of the rejection() method in JavaScript

function exe(resolve, reject){
  reject(new Promise((resolve, reject)=>{
    resolve("second promise succeed");
  })) ;
}

const prom = new Promise(exe);

prom.then(value=>{
  console.log("Resolved handler");
  console.log(value);
},
failed=>{
  console.log("Failed handler");
  console.log(failed);
});

Output:

Failed handler

Promise {<fulfilled>: "second promise succeed"}

As you can see, in the first promise, the `reject` function gets called, but the argument to this function is another promise that actually succeeds. But even then, the rejection handler of the first promise gets called and for this reason, we got the fulfilled promise that passed as its argument.

Alright, in the next couple of sections we will focus more on the `then` method as well as a couple of other methods, including the `catch` and `finally`.

Related Resources:

JavaScript Promise then() Method Tutorial

JavaScript Promise catch Method Tutorial

JavaScript Promise finally Method Tutorial

JavaScript Promise resolve() Method Tutorial

JavaScript Promise reject() Method Tutorial

JavaScript Promise race() Method Tutorial

JavaScript Promise any() Method Tutorial

JavaScript Promise all() Method Tutorial

JavaScript Promise and Microtask Queue Tutorial

Leave a Reply