Promises

Let's look at the future result of asynchronous operations

Introduction

As the headline of this article rightly states, Promises represent the future result of async operations. Given the async context, the values represented by Promise objects may be available instantly or at some time in future or in yet another cases they may never be available. In this tutorial, our objective is to understand promises and how they fit into the world of Node.js and Javascript.

What exactly is a Promise

A promise is simply an object which represents the result of an async operation. A promise can be in any of the following 3 states :

  1. pending :: This is the initial state, means the promise is neither fulfilled nor rejected.
  2. fulfilled :: This means the promise has been fulfilled, means the value represented by promise is ready to be used.
  3. rejected :: This means the operations failed and hence can't fulfill the promise.

Apart from the states, there are three important entities associated to promises which we really need to understand

1. executor function :: executor function defines the async operation which needs to be performed and whose result is represented by the promise. It starts execution as soon as the promise object is initialized.

2. resolve :: resolve is a parameters passed to the executor function , and in case the executor runs successfully then this resolve is called passing the result.

3. reject :: reject is another parameter passed to the executor function , and it is used when the executor function fails. The failure reason can be passed to the reject.

So whenever we create a promise object, we've to provide Executor, Resolve and Reject. We'll see that shortly using examples below.

# Install Promise

In order to be able to do anything useful using promises, you need to first install them using the command shown below.

 
           
                 npm install promise
           
        

# Write your first promise

In the following function , we emulate an async function by using setTimeout after which we return the square of the number if the number is even and in case the number is odd, we simply reject the promise.

 
         
var promise = require('promise');

    var squareP = ( p ) =>  {
    return new Promise( ( resolve , reject ) => { 
        setTimeout( () => { 
            if ( p % 2 == 0 ) {
                resolve( p * p ) 
            }
            else {
                reject( p )
            }
        } , 500 )
    });
};


// calling squareP with 2 which is even 

squareP( 2 )
  .then( ( data ) => { console.log( data ) } )
  .catch( ( err ) => console.log(err) );

// calling squareP with 3 which is odd 

squareP( 3 )
  .then( ( data ) => { console.log( data ) } )
  .catch( ( err ) => { console.log( err) })
 
 

You can copy paste the above code into a file lets say next.js and then execute the same using the following in terminal

 
           
             node next.js
           
        

As you might observe, the first promise is fulfilled while the second one is rejected

Practical Value

In the above example we had only a single operation, imagine the scenarios where you may have to chain multiple operations together. The only problem with callbacks is that they get messy because readibility is inversely proportional to the chain length. Below let's look at a slightly complicated version of the above same example. What we do is we square a number and pass the result to next function which do the further squaring. The operation we're performing may sound foolish but the idea is to understand how promises make deep chaining very easy. The example also shows how we can keep on passing the results through the chain.

 
  
      
var promise = require('promise');

 var getP = ( p ) => {
    return new Promise( ( resolve , reject ) => { 
        setTimeout( () => { 
            if ( p % 2 == 0 ) {
                resolve( p * p ) 
            }
            else {
                reject( p )
            }
        } , 500 )
    });
};

var getQ = ( p ) => {
    return new Promise( ( resolve , reject ) => { 
       
        setTimeout( () => {
            if ( p % 2 == 0) {
                resolve( p * p);
            }
            else {
                reject( p );
            }
        } , 200 )
    });
};

var getR = ( p ) => {
    return new Promise( ( resolve , reject ) => {
        setTimeout( () => {
            if ( p % 2 == 0) {
                resolve( p * p );
            }
            else {
                reject( p ); 
            }
        } , 100 )
    });
};

getP( 2 )
  .then( ( data ) => { return getQ(data) } )
  .then( ( data2 ) => { return getR(data2) } )
  .then( ( data3 ) => { console.log(data3 ) } )
  .catch( ( err ) => console.log(err) );

   

The function getP , getQ and getR all return promises which are chained and the results of each operation being passed to the next. We can save the above code in a file next2.js and run as follows

 
           
             node next.js
           
        

The result turns out to be ::

 
           
             256 
           
        

Summary

In this tutorial, we learned how we can use promises to enhance the readibility and hence reduce the complexity of node.js code using Promises. We also saw how to chain promises and pass data around.

Love Code. Live Code.

RISHABH.iO