In this article, we will go through the concept of javascript promise. After reading this article, you will be able to
1. Understand what is a promise and why it is created.
2. How to create a promise.
3. Resolve or reject a promise.
4. Handle error in promise.
5. Chaining multiple promises.
What is a javascript promise
A promise allows you to work with asynchronous operations or tasks. Asynchronous means an operation which executes without blocking other operations.
Example, consider a facebook page. When you open it, some portions of the page display first while the posts load later.
Here, loading of posts is performed as an asynchronous operation.

A promise allows you to perform a time taking task and process the result of the task as and when it(the result) becomes available without blocking the other operations.
Promise was introduced in ES6.
How to create promise?
A promise is created using constructor of Promise class.
This constructor expects a function with two arguments. as shown below.

// create a promise
const promise = new Promise(function(resolve, reject) {

});

Inside the function body, the task which the promise is supposed to do is written. This is usually a task that takes time to complete or the task which you want to perform asynchronously.
If we take the facebook example, the task of fetching posts would be written inside the function body.

Promise constructor
When creating a promise, a function is supplied in the Promise constructor. This function has two arguments : resolve and reject but they can be given any name of your choice.

These arguments are themselves functions and are used to signify whether the task written in promise executed successfully or failed.
If the task executed successfully, then you call resolve function and pass it a value, if required.
Similarly, if the task failed due to some reason, then reject function is called as shown below.

// create a promise
const promise = new Promise(function(resolve, reject) {
   // asynchronous task
   if(successful) {
      resolve('Success!');
   } else {
      reject('Error!');
   }
});

Remember that the task that the promise is supposed to execute should be written inside the promise constructor and it starts as soon as the promise is created.

Promise states
A promise has different states during its lifecyle. It can be in any of the following states according to the task it performs.
1. Pending
When the promise is created and while it is executing its task, it remains in the “pending” state.
If you do not call resolve or reject functions, the promise will be in “pending” state forever even if its task completes successfully.

2. Fulfilled
A promise enters “fulfilled” state after you call resolve function. This indirectly means that when its task completes successfully since then only you would like to call resolve.
But, even if you call resolve in case of an error, the state of promise will be “fulfilled”.

2. Rejected
State of the promise becomes “rejected” when reject function is called which means that the task of promise failed due to some reason.

How to use promise: then() method
A promise executes a task asynchronously and when the task completes, you need some way to handle the result.
Coming back to facebook example, suppose a promise is fetching posts. When the post data is fetched, there should be a mechanism to display the post data on web page.

This is done using then() method of a promise. then() method is automatically invoked when you call resolve() or reject() from a promise.
Thus, then() is a callback function.

then() method takes two functions as arguments: One for handling the resolve() callback and other for handling reject() callback.

If you provide only one function argument, then it will be considered as a handler for resolve() callback. Thus, then() takes at least one function as argument.

These functions may or may not accept a value. If they accept a value, then it is populated with the value supplied by the resolve()  and reject() functions.

Working of then() will be better understood with the below illustration.
how promise works

Promise example
Below is an example of how a promise is created and used to perform asynchronous task processing.

const p = new Promise(function(resolve, reject) {
      // time taking asynchronous task
      setTimeout(function() {
         // array of posts
         const posts = [{"postid": 1, "description": "Post One"},
                        {"postid": 1, "description": "Post One"}];
         // resolve promise
         resolve(posts);
      },2000)
}); 

// other tasks
p.then(function(value) {
   console.log(value);
});

Above example creates a promise with a function as an argument. For simulating a time taking task, setTimeout() function is used.
Suppose the task written in promise returns an array of objects. When the task completes, resolve() is called with the array as an argument.

After the promise definition, then() method is called on it. then() accepts a function as an argument which is the callback function for resolve() as explained in the last section.
As soon as resolve() is called, the function written inside then() is invoked. The argument to this function is populated with the value supplied by resolve() function.

Here is the output of the above code.
javascript promise exampleOutput shows an array of post objects that was returned by the resolve() method.

When the promise is executing, other tasks can also execute simultaneously. Thus, a promise performs a task asynchronously.

Handling errors
There may be a possibility that the task performed by a promise fails or results in an error. If there is an error, then you need to call reject() from inside the promise.
After calling reject(), we should also handle the error.
There are following two ways to handle the error condition after calling reject(), any one of these may be used.

1. Error handler function in then()
If there is an error during task processing in a promise, then call reject() function from inside the promise body.
As stated earlier, then() accepts two functions as arguments where the second one is a callback function which is automatically called when reject() is called from promise.
Value passed as argument to reject() becomes available as an argument to the second argument of then(). Example,

const p = new Promise(function(resolve, reject) {
      // time taking asynchronous task
      setTimeout(function() {
         
         // error condition
         reject('Oops! An error occurred');
      },2000)
}); 
// other tasks
p.then(function(value) {
   console.log(value);
}, 
function(error){
 console.log(value);
});

Above example prints

Oops! An error occurred

Remember that only the second argument function to then() will be considered as error handler function.
2. Using catch()
Similar to then(), promise provides a catch() method, which acts as a handler for error raising inside promise.
catch() accepts a function as argument. It is inside this function that you write the error handling mechanism.
Argument to this function receives the value sent by reject(). Example,

const p = new Promise(function(resolve, reject) {
      // time taking asynchronous task
      setTimeout(function() {
         // error condition
         reject('Oops! An error occurred');
      },2000)
}); 
// other tasks

p.then(function(value) {
   console.log(value);
});

// error handling using catch
p.catch(function(e){
 console.log(e);
});


Promise chaining

Promises can be chained meaning you can call then() multiple times one after another without creating a new promise.
This is because then() returns a promise and you can always call then() on a promise. Value returned by the first then() is implicitly passed to the second then() and so on. Example,

function increment(seconds) {
  // create promise
  const p = new Promise(function(resolve, reject) {
      // increment argument value
      seconds++;
      // resolve promise
      resolve(seconds);
  }); 
  return p;
}

// promise chaining
increment(0).then(increment).then(function(v){console.log(v);})

Above example demonstrates promise chaining and it can be broken into multi-lines to understand how it works

1. increment(0).
2. then(increment).
3. then(function(v) { console.log(‘Final result is ‘ + v); });

1. increment() function is invoked with 0 as argument. It creates a promise and returns it. The promise increases the value of function argument by 1 and calls resolve().

2. Since increment() returns a promise, we can call then() over it. Now, then() expects a function as argument and we are passing it increment() which is a function.
then() returns a value by calling resolve() and this returned value is implicitly passed to increment().

3. Step 2 calls increment() which again performs Step 1 and returns a promise. then() is called on this promise and prints the value returned by the promise.

Output of this example will be

Final result is 2

Promise.all()
all() method accepts an array of multiple promises and waits till all promises call resolve() or any one promise calls reject(). Example,

// create a promise
const p1 = new Promise(function(resolve, reject) {
        setTimeout(function() {
                resolve('Promise 1');
        }, 2000)
}); 

// create another promise
const p2 = new Promise(function(resolve, reject) {
        setTimeout(function() {
          resolve('Promise 2');
        }, 1000)
}); 

// invoke all with both the promises
Promise.all([p1,p2])
.then(function(v){ console.log(v); });

Above code waits for 2 seconds and then prints

[ “Promise 1”, “Promise 2”]

If any one of the promise calls reject() or results in an error, then all() returns an error. In that case, it does not wait for other promises to finish.
Example,

// create a promise
const p1 = new Promise(function(resolve, reject) {
        setTimeout(function() {
          resolve('Promise 1');
        }, 2000)
}); 

// create another promise
const p2 = new Promise(function(resolve, reject) {
        setTimeout(function() {
          reject('Error!');
        }, 1000)
}); 

// invoke all with both the promises
Promise.all([p1,p2])
.then(function(v){ console.log(v); })
.catch(function(e){ console.log(e); });

Above code will wait for 1 second and then print

Error!

Note that in this example, we have used catch() method to handle reject(). But you may also add a second argument function to then().

Promise.race()
race() also accepts an array of promises but it returns the value from the promise that calls resolve() or reject() first. Thus, the result will be the value of promise which resolves or rejects before all other promises. Example,

// create a promise
const p1 = new Promise(function(resolve, reject) {
        setTimeout(function() {
          resolve('Promise 1');
        }, 2000)
}); 

// create another promise
const p2 = new Promise(function(resolve, reject) {
        setTimeout(function() {
          resolve('Promise 2');
        }, 1000)
}); 

// invoke all with both the promises
Promise.race([p1,p2])
.then(function(v){ console.log(v); })
.catch(function(e){ console.log(e); });

Above code will wait for 1 second and then print

Promise 2

since the second promise will resolve first.
If there are multiple promises that call resolve() or reject() at the same time, then the first one in the argument array to race() will win.
Why create promise
Now when you have learnt about promise syntax and chaining, you are ready to understand the benefit you get from it.
A promise is used to perform asynchronous operation. You might say that the same can be achieved by a callback function.
But when there are multiple callback functions that are dependent on each other or nested inside each other, then it becomes hard to maintain them.

Consider the code snippet below.

setTimeout( function(v1){
   setTimeout(function(v2) {
      setTimeout(function(v3) {
       setTimeout(function(v4) {
  
     }, 1000); 
      }, 1000);
   }, 1000);
}, 1000);

This code is often referred to as Callback hell since it is very difficult to manage.
Promise solves this problem by chaining and you don’t need to nest more than one level. Thus, below code is very easy to maintain.

taskOne()
.then(function(){
  return taskTwo();
})
.then(function() {
  return taskThree();
})
.then(function() { 
   return taskFour(); 
});


Arrow functions in promise

Till now we have seen functions at multiple places while using promises. In place of these functions, you could also use javascript arrow functions.
Arrow functions were also added in ES6 and they enable you to write functions in a shorter syntax. If you are not familiar with them, refer this article.

Using arrow functions, promise example can be modified as below.

const p = new Promise((resolve, reject) => {
      // time taking asynchronous task
      setTimeout(() => {
         // array of posts
         const posts = [{"postid": 1, "description": "Post One"},
                        {"postid": 1, "description": "Post One"}];
         // resolve promise
         resolve(posts);
      },2000)
}); 

// other tasks
p.then((value) => {
   console.log(value);
}, (error) => {
 console.log(error);
});

That is all on promise in javascript ES6. Click the clap if you liked it.

1

Close Menu

Never Miss an article !

Get the new post delivered straight into your inbox, enter your email and hit the button

You have successfully subscribed to the newsletter

There was an error while trying to send your request. Please try again.

codippa will use the information you provide on this form to be in touch with you and to provide updates and marketing.