Node JS Promises, Practical uses

In last article I discussed the node js callback & native (es6) promises.

Their are more cases where promises come handy.

Let a case where we need to get a user information for given id, but information is in different sql tables/mongo collections.

// As promise passed resolved object into chain, So we need to use that one

getUserInfo(userId) {
  // Return Promised Info
  return userModel.findOne({_id: userId}).exec();
}
getUserAddressInfo(preResults) {
  // Return Promised having info merged with preResults 
  return userAddrModel.findOne({_id: preResults._id}).exec().then((results) => {
   return [preResults, results]
  });
}
getUserExperienceInfo(preResults) {
  // Return Promised having info merged with preResults 
  return userExpModel.findOne({_id: preResults._id}).exec().then((results) => {
   return [preResults, results]
 });
}

getUserEducationInfo(preResults) {
 // Return Promised having info merged with preResults 
 return userEduModel.findOne({_id: preResults._id}).exec().then((results) => {
   return [preResults, results]
 });
}

getUserInfo(userId)
 .then(getUserAddressInfo)
 .then(getUserExperienceInfo)
 .then(getUserEducationInfo)
 .then((results) => {
    console.log(results)
 }).catch(err => {
    console.error('Getting error')
 });

Chain approach in last article is not very effective as that will block the node js event model which reduce performance.

We need parallel execution of functions but still need their output at final place. We need to change our code some thing like that

getUserInfo(userId) {
  return userModel.findOne({_id: userId}).exec();
}
getUserAddressInfo(userId) {
  return userAddrModel.findOne({_id: userId}).exec();
}
getUserExperienceInfo(userId) {
  return userExpModel.findOne({_id: userId}).exec();
}

getUserEducationInfo(userId) {
  return userEduModel.findOne({_id: userId}).exec();
}

NOTE : exec is Mongoose API function for return promised data.

Promise.all([
  getUserInfo(userId), 
  getUserAddressInfo(userId), 
  getUserExperienceInfo(userId),
  getUserEducationInfo(userId)
]).then((results) => {
  console.log(results)
}).catch(err => {
  console.error('Getting error')
});

Here all functions called parallel by Promise.all api method in iterator (array) way. Result would be an array where first element return the result of getUserInfo, second on getUserAddressInfo and so on…

If we need to apply function to an array’s all values, We can still use promises using map (or other you prefer). Let we need some user profile content from public url for group of users in array.

const promises = userIds.map((userId) => {
 return new Promise((resolve, reject) => {
   http.get('http://www.example.com/user' + userId, function(response) {
     resolve(response);
   }); 
 }); 
});

Promise.all(promises).then((results) => {
  console.log(results);
}).catch(err => {
  console.error(err);
});

Other promise api function than Promise.all is Promise.race which return the first function who completed its execution.

Promise.all([
  getSite1Feeds(), 
  getSite2Feeds(), 
  getSite3Feeds(), 
  getSite4Feeds(), 
]).then((results) => {
  console.log(results); // Whoever comes first
}).catch(err => {
  console.error('Getting error')
});

Mozilla Promises API Documentation

 

 

Callbacks & Promise in node js

Today i will share the Node JS callback and promise system. Node JS asynchronous event based language which mean system not wait for task for completion and forward to next instruction. So as an example if we try to read a file from file system and then print read contents that may not work.

const fs = require ("fs");
let content = fs.reafile ("file.txt"):
console.log (content):

In above code, interpretor jump to console log even before read file call completion due to asynchronous behavior.
This issue is resolved by Node JS by making all its core APIs async friendly through callbacks. Above example actually work like below.

const fs = require ("fs");
let content = fs.reafile ("file.txt", function (err, data){
     if (err ){
          console.log (err);
     }
     console.log (data):
}):

Here readfile api provide a callback function which executed after file read operation. It have two arguments err and data. Data have the success response, in case of readfile api, file contents.
Node JS core APIs work like that. Provide a callback function with error and response as parameters. We can implement our callbacks similar to this for asynchronous tasks.

funtion asyncfunction (inp, callback ){
     // do some asyns task
     const http = require ("http");
     http.get (url, function (err, response){
         callback (response);
     });
}

Above function can be used like

asyncfunction( data, function (httpResponse) {
      console.log( httpResponse);
});

In this case we can get interesting pattern like below.

 func1(data, function() {
    data.mod1 = 1;
    func2(data, function() {
        data.mod2 = 2;
        func3(data, function() {
            data.mod3 = 3;
            func4(data, function() {
                 data.mod4 = 4;
                 console.log( data);
            })
        });
    });
});

Above code show hierarchy of callbacks, Also famously called Callback Hell. This is problematic due to Poor readability & Poor manageability. Their are multiple solutions for ignore callback hells.
First to use modular code like I previously done in asyncfunction.

Second approach is to use Promises. Promise give us better control of asynchronous code.
Promise have two results states. Resolve & Reject. In Core Node JS we can use promise like that

function MyPromisedFunc() {
    return new Promise( function(resolve, reject) {
         http.get(url, function(err, response) {
             if( err ) {
                  reject(‘Error in http response’)
             }
             resolve(response);
        });
   });
 }

return MyPromisedFunc() .then(function(response) {
     console.log(response);
 }).catch(function(err) {
     console.log(err);
 });

Above code is more readable and manageable then callback code. Any time of our async code when we get actual response, we only need to resolve promise, If we get error the we reject the promise.
This further handle by then & catch blocks.
This is more look clear in multiple async function which need to run synchronously.

return MyPromisedFunc1()
     .then(MyPromisedFunc2)
     .then(MyPromisedFunc3)
     .then(MyPromisedFunc4)
     .then(function(response) {
          console.log(response);
     }).catch(function(err) {
          console.log(err);
     });

Now we executed four asynchronous functionalities in sync manner with better manageability.
Promise core api functionality is still very much limited in terms of functionality compare to third party Promise libraries like bluebird, Q Promise and more.

Example in bluebird support execution in parallel with better control.

const bluebirdPromise = require(‘bluebird’);
return bluebirdPromise.all([
     MyPromisedFunc1(),
     MyPromisedFunc2(),
     MyPromisedFunc3(),
     MyPromisedFunc4() ],
     .then(function(responseArray) {
           console.log(responseArray[0]);
           console.log(responseArray[1]);
           console.log(responseArray[2]);
           console.log(responseArray[3]);
     }).catch(function(err) {
          console.log(err);
     });