1

I'm creating an API using Express JS (Express 4) framework. I'm pretty new to NodeJS so I would like to know the best way to perform multiple async calls inside the same function.

For this example, I've got a function called Login in my Login Controller. Inside this function, let's say I gotta make quite a few async calls for authenticating a user, saving login info and similar functionalities like that.

But for some async calls, data to be processed should be fetched from the previous async call (they are dependent functions) and some functions are not like that.

Right now, this is how I'm doing the calls.

exports.login = function (req, res) {

    var user = {
      email: 'fakeemail@id.com',
      password: 'password'
    };
    //Async call 1
    Login.authUser(user, function (err1, rows1) {
        var user_id = rows1[0].id;

        //Async call 2 (depends on async call 1 for user_id)
        Login.fetchUserDetails(user_id, function (err2, rows2) {

            //Async call 3
            Login.updateLoginInfo(param3, function (err3, rows3) {

                //Some functionality occurs here then async call 4 happens

                //Async call 4
                Login.someOtherFunctionality(param4, function (err4, rows4) {
                    //return response to user
                    res.json({
                        success: true
                    });
                });

            });
        });

    });
};

Now all these async calls are nested. Is there any other way I can do this?

P.S: I didnt add error handling in this example

Smokey
  • 1,857
  • 6
  • 33
  • 63

4 Answers4

2

you can use promise as well. It will make you syntax more pretty. Your code will look like

Login.authUser(user).
then(fetchUser).
then(updateLoginInfo).
then(someOtherFunctionality).
catch(function(error){
//log your error or whatever
});
Shahzeb Khan
  • 3,582
  • 8
  • 45
  • 79
1

You can use Promise as suggested by Shahzeb.

Promises are objects that get resolved in future (asynchronous). Once a Promise is completed it either resolves or rejects. All promises resolved are then ed and those get rejected are catch ed

pseudo code

let myPromise = function() {
   return new Promise(function(resolve, reject) {
    resolve('foo');
  });
};

myPromise().then( (v) => {
  console.log(v);
})
zamil
  • 1,920
  • 4
  • 17
  • 32
1

Use Promise Chaining

new Promise(function(resolve, reject) {

  setTimeout(() => resolve(1), 1000); // (*)

}).then(function(result) { // (**)

  alert(result); // 1
  return result * 2;

}).then(function(result) { // (***)

  alert(result); // 2
  return result * 2;

}).then(function(result) {

  alert(result); // 4
  return result * 2;

});
More details refer Promise Chaining and chain promises in javascript
Vipin PS
  • 422
  • 4
  • 5
1

Using async/await (Requires Node.js v7.6) This strategy also uses promises. In my opinion it improves readability since you are refactoring out each individual promise call into separate methods.

Codepen

// mock async calls
const authUser = user => Promise.resolve([{ id: 1 }]); // returns users id
const fetchUserDetails = user_id => Promise.resolve({ name: 'Fred', age: '10000' }); // returns users details
const updateLoginInfo = param3 => Promise.resolve({ status: 'success' }); // returns success?
const someOtherFunctionality = param3 => Promise.resolve({ field: 'value' }); // returns something

// all async functions return a promise
const login = async (/*req, res*/) => {

  // User object
  const user = {
    email: 'fakeemail@id.com',
    password: 'password'
  };

  // Async call 1
  console.log(`Authorizing user...`);
  const rows1 = await authUser(user);
  const user_id = rows1[0].id;
  console.log(`User ${user_id} authorized.`);

  // Async call 2 (depends on async call 1 for user_id)
  console.log(`Fetching user detail...`);
  const rows2 = await fetchUserDetails(user_id);
  console.log(`User Detail was fetched: ${JSON.stringify(rows2)}`);

  // Async call 3
  console.log(`Updating login info...`);
  const param3 = `something`;
  const rows3 = await updateLoginInfo(param3);
  console.log(`Login info was successful: ${JSON.stringify(rows3)}`);

  // Some functionality occurs here then async call 4 happens
  console.log(`\nDoing stuff after async call 3, but before async call 4....\n`);

  // Async call 4
  console.log(`Async call 4...`);
  const param4 = `something`;
  const rows4 =  await someOtherFunctionality(param4);
  console.log(`END OF LOGIN FUNCTION`);

  return 'returned value';
}

// run the async function
login()
  .then(result => {
    // respond
    // res.json({ success: true });
    console.log(`Promise value: ${result}`);
    console.log(`Response: { success: true }`);
  })
  .catch(err => {
    console.log(err);
  })
thomann061
  • 629
  • 3
  • 11