user3741852
user3741852

Reputation: 47

How to return a single promise after for loop where every element of an array inside loop do multi async calls

I Have a array of objects which i need to clone with different values.

Those values i'll get from each promise finally after preparing main modified array of object i'll have to save this. So i many need this as one single promise.

I not sure how to do it.

Here is the example we need to clone oldUser data. Say old user has credit score = 100; but for new user default credit will be created randomly by system.

For each user in the array of users few details has to get updated using async call. This is the requirement

function getUserCreditScore(user){
  var url = '/someurl';
  return $http.get(url).then(function(res){
    user.creditScore = (res.data) ? res.data : 0;
  });
}

function getUserRecomandations(user){
   var url = '/someurl';
  return $http.get(url).then(function(res){
   user.recommendation = (res.data) ? res.data : 'basic recommendation';
  });
}  

function getUserHelpInfo(user){
   var url = '/someurl';
  return $http.get(url).then(function(res){
   user.helpInfo = (res.data) ? res.data : 'Help Info';
  });
}  


function clone(){
  var newUsers = angular.copy(oldUsers);

  for (var i=0; i<newUsers.length; i++){
    newUsers[i].id = undefined;
    getUserCreditScore(newUsers[i]);
    getUserRecommendation(newUsers[i]);
    getUserHelpInfo(newUsers[i]);
  }

  var promises = _.map(newUsers, user => user.save());
  $q.all(promises).then(function (data) {
   console.log(data);
  }
}

Upvotes: 0

Views: 69

Answers (2)

Jaromanda X
Jaromanda X

Reputation: 1

You'll need to Promise.all on an array of Promises that are returned by getScreditScore

something like

function getCreditScore(){
    var url = '/someurl';
    return $http.get(url).then(res => (res && res.data) ? res.data : res);
}

function clone(){
    var newUsers = angular.copy(oldUsers);

    Promise.all(
        newUsers.map(newUser => {
            newUser.id = undefined;
            return getCreditScore()
            .then(result => newUser.creditScore = result);
        })
    ).then(results => // results will be an array of values returned by the get in getCreditScore(newUser)
        Promise.all(newUsers.map(user => user.save()))
    ).then(data =>
        console.log(data); // this will be the result of all the user.save
    );
}

Note: the newUser.creditScore is set in the .then in the newUsers.map callback - (minimal change to my original answer)

Alternatively, passing user to getCreditScore

function getCreditScore(user){
    var url = '/someurl';
    return $http.get(url)
    .then(res => (res && res.data) ? res.data : res)
    .then(score => user.creditScore = score);
}

function clone(){
    var newUsers = angular.copy(oldUsers);

    Promise.all(
        newUsers.map(newUser => {
            newUser.id = undefined;
            return getCreditScore(newUser);
        })
    ).then(results => // results will be an array of values returned by the get in getCreditScore(newUser)
        Promise.all(newUsers.map(user => user.save()))
    ).then(data =>
        console.log(data); // this will be the result of all the user.save
    );
}

Personally, I'd write the code

function getCreditScore(){
    var url = '/someurl';
    return $http.get(url).then(res => (res && res.data) ? res.data : res);
}

function clone(){
    var newUsers = angular.copy(oldUsers);

    Promise.all(
        newUsers.map(newUser => {
            newUser.id = undefined;
            return getCreditScore()
            .then(result => newUser.creditScore = result)
            .then(() => newUser.save())
            .then(() => newUser);
        })
    ).then(data =>
        console.log(data); // this will be the newUsers Array
    );
}

This assumes, though, that you don't need to wait for all the $http.get before running the user.save() - in fact this may be a little (very little) more performant as the newUser.save and $http.get will run in tandem

Upvotes: 1

yzfdjzwl
yzfdjzwl

Reputation: 117

Ok, I know your meaning, you want your every element of your array do something that is async.

So you can use map and Promise.all. Here is my code:

const asyncFunction = (item, cb) => {
  setTimeout(() => {
    console.log(`done with ${item}`);
    cb();
  }, 1000);
}

let requests = [1, 2, 3].map((item) => {
  return new Promise((resolve) =>{
    asyncFunction(item, resolve);
  });
});

Promise.all(requests).then(() => console.log('done'));

Upvotes: 0

Related Questions