1

I'm trying to create a web application using nodeJS and I'm stuck because of the asynchronous nature of nodeJS.

I have three different environments and based on user input from html form I should check if a user exists in the selected environment.

The html will have 3 check boxes and user can select any number of environments.

if(Dev_Environmnet){
    getUserDatafromEnvironment(user,environment, function(callback1)){
        if(callback1.error){
            // User Does Not Exist Or credentials are wrong
        }
        else{
            //get User API 
        }

    });
}
if(PVS_Environmnet){
    getUserDatafromEnvironment(user,environment, function(callback1)){
        if(callback1.error){
            // User Does Not Exist Or credentials are wrong
        }
        else{
            //get User API 
        }

    });
}
if(Prod_Environmnet){
    getUserDatafromEnvironment(user,environment, function(callback1)){
        if(callback1.error){
            // User Does Not Exist Or credentials are wrong
        }
        else{
            //get User API 
        }

    });
}

once this is done I need those results from the callbacks to print it to another HTML page. this is what I need to show on the next page

DEV - API key gdeuysgdsgddiudgqwywdgAguiegdhsiw
pVS - user does not exist or credentials are wrong
Prod - APYI Key ugehdfiyugfugew%$%$udisfiuhygyig

I'm not able to get all these values at once. Can someone help me?

Maciej Treder
  • 11,866
  • 5
  • 51
  • 74
Rao572
  • 19
  • 3
  • 1
    Convert your calls to `getUserDatafromEnvironment` so that it returns a promise, and then use Promise.all(array) to process all results at once. – some Feb 11 '18 at 22:06
  • Hi thank you for reposnding. Can you show me how to do that..? I mean using code. – Rao572 Feb 11 '18 at 22:07
  • `Promise.all()` is no good because it'll require all three mechanisms to resolve. AFAICS the OP wants _any one or more_ to succeed. That said, if the functions are wrapped so that they _always_ resolve with a success/fail result instead of generating a `reject` on failure that could still work. – Alnitak Feb 11 '18 at 22:11
  • @Alnitak could you please elaborate on what you said here. – Rao572 Feb 11 '18 at 22:20
  • @Alnitak `Promise.all()` is perfect to use for this. You just need to handle errors in each provider, and return null or something like that to the promise that is in the array to Promise.all(). – some Feb 11 '18 at 22:26
  • @Alnitak I wrote my comment before I saw that you had edited your answer. – some Feb 11 '18 at 22:31

4 Answers4

0

Not sure what you mean by "get them at once" if you mean "know when all 3 async operations are completed", then there are a few ways you could do this, suggest you look into turning your async methods into promises (How do I convert an existing callback API to promises?) and use Promise.all or look at using async and await.

Woody
  • 7,578
  • 2
  • 21
  • 25
0

Based on your pseudo code, something like this.

// I assume that you need special functions to get the information
// from different providers.

function getUserFromPVS(user) {
  return new Promise( (resolve, reject) => {
    // special code to get user from PVS
    return resolve(userdata);
  });
}
function getUserFromDev(user) {
  return new Promise( (resolve, reject) => {
    // special code to get user from Dev
    return resolve(userdata);
  });
}
function getUserFromProd(user) {
  return new Promise( (resolve, reject) => {
    // special code to get user from Prod
    return resolve(userdata);
  });
}

// Converted the call to getUserDatafromEnvironment so it is a promise.
function getUserData(flagSelected, user, environment, req) {
  return new Promise( (resolve, reject) => {
    if (!flagSelected) return resolve(null); // Returns null if not selected
    getUserDatafromEnvironment(user,environment, (cb) => {
      if (cb.error) {
        return resolve(null); // Return NULL instead of rejecting.
      } else {
        // Call to promise that return user information
        // I assume you need different functions for
        // each provider
        return resolve( req(user) )
      }
    })

  });
}
Promise.all([
  getUserData( PVS_Environmnet, user, environment, getUserFromPVS ),
  getUserData( Dev_Environmnet, user, environment, getUserFromDev ),
  getUserData( Prod_Environmnet, user, environment, getUserFromProd ),
]).then( (results) => {
  // results[0] has result from Dev or is null
  // results[1] has result from PVS or is null
  // results[2] has result from Prod or is null
}).catch(
  (error) => console.error(error)
)
some
  • 48,070
  • 14
  • 77
  • 93
0

First, you can wrap your getUserDatafromEnvironment so that it returns a Promise:

function getUserDatafromEnvironmentP(flag, user, environment) {
    if (!flag) return Promise.resolve(undefined);  // method not selected

    return new Promise(function(resolve) {
        getUserDatafromEnvironment(user, environment, function(callback) {
            resolve(!callback.error);
        })
     });
}

You can then call your three methods and pass them to Promise.all() which will wait until all three have completed and tell you the results:

let p1 = getUserDatafromEnvironmentP(Dev_Environmnet, user, environmnet);
let p2 = getUserDatafromEnvironmentP(PVS_Environmnet, user, environmnet);
let p3 = getUserDatafromEnvironmentP(Prod_Environmnet, user, environmnet);

let result = Promise.all([p1, p2, p3]).then(
    function(results) {
        // results[0 .. 2] will contain the three results
        // undefined for "not used", false for "failed", true for "ok"
        .. continue with processing here
    })
);

// you can't do anything useful here because the above code is async

NB: generally I'd frown up using a resolve to indicate failure, but in this case it seems appropriate because of subsequent use of Promise.all().

Alnitak
  • 334,560
  • 70
  • 407
  • 495
-1

You should keep calls to the other checks inside callbacks from previous ones:

checkOne(someArgs, (callback) => {
    let checkOneResult = true;
    if (callback.error)
        checkOneResult = false;
    checkTwo(someArgs, (callback) => {
        let checkTwoResult = true;
        if (callback.error)
            checkTwoResult = false;

        //here I got result from both checks:
        console.log(checkOneResult);
        console.log(checkTwoResult);
    });
});
Maciej Treder
  • 11,866
  • 5
  • 51
  • 74
  • This will not work for me becuase the user decides which environments to get the user API from. If the user selects only prod environment I need this result from only prod. And the output should only show Prod API Key hgveufygsiyefgaesdiu86538 – Rao572 Feb 11 '18 at 22:16
  • this also _serialises_ the three accesses instead of running all of them concurrently – Alnitak Feb 11 '18 at 22:32