0

I just can't seem to get a hang of JavaScript promises.

In Parse, I have an attribute on a user that stores an array of Facebook friends IDs. When a new user logs in through Facebook for the first time I want to iterate through their Facebook friends that are using the app, then update those user's Facebook friends array to include this new user.

So... in user before_save I have this:

var friendsArray = user.get("facebookFriends");
// Iterate through all Facebook friends
_.each(friendsArray, function(facebookId){

   // Retrieve the Facebook friend user 
   var query = new Parse.Query(Parse.User);
   query.equalTo("facebookId", facebookId);

   console.log("this executes");
   query.find().then( function(){
       var user = results[0];
       // This does not execute
       console.log("Need to update " + user.get("displayName") + "'s facebook friends");
       return Parse.Promise.as();
   });
}

My problem is not that different than another previous problem I encountered (Parse JavaScript SDK and Promise Chaining), except that this time I need the results of the async call before I can begin updating the user's Facebook friends array.

Community
  • 1
  • 1
toddg
  • 2,863
  • 2
  • 18
  • 33

1 Answers1

1

The way to accomplish this is with Parse.Promise.when() which is fulfilled when array of promises passed to it are fulfilled. And the loop can be made prettier as _.map().

var friendsArray = user.get("facebookFriends");
var findQs = _.map(friendsArray, function(facebookId){

    // Retrieve the Facebook friend user 
    var query = new Parse.Query(Parse.User);
    query.equalTo("facebookId", facebookId);

    console.log("this executes");
    return query.find();
});

return Parse.Promise.when(findQs).then(function(){
    var user = results[0];
    // This will work now
    console.log("Need to update " + user.get("displayName") + "'s facebook friends");
    return Parse.Promise.as();
});

The results will be an array of arrays -- since find returns an array --passed as var-args, and underscore _.toArray() is useful here, i.e.

return Parse.Promise.when(finds).then(function() {
    var individualFindResults = _.flatten(_.toArray(arguments));
    // and so on
danh
  • 62,181
  • 10
  • 95
  • 136
  • It's not immediately obvious why you might need to flatten the args? – Roamer-1888 Feb 15 '15 at 08:40
  • @Roamer-1888, find() returns an array of matches, so the args will be an array of arrays. This might be desirable in some cases, but not in the OP. – danh Feb 15 '15 at 15:18
  • Thanks! It works, but I guess I don't really understand why mine didn't work. – toddg Feb 16 '15 at 14:37
  • 1
    Your code tries to start several queries from a loop. The loop completes before all of the queries have. Sometime soon after the loop your code finishes executing , never giving the remaining queries a chance. When() keeps the execution context around until all promise passes to it are fulfilled. – danh Feb 16 '15 at 15:24