user3353762
user3353762

Reputation: 103

Understanding JavaScript promises in Parse

I am developing an app in Parse and I'm trying to understand promises. I'm not finding very many working examples other than the very simple ones here: https://parse.com/docs/js/guide.

I'm querying the _User table. Then I loop through the users in an _.each loop. I'm running 2 cloud functions inside the loop for each iteration. At what point do I create the promise? Do I create one for each cloud function success within the loop? Or do I push each success return value onto an array and make that the promise value outside of the loop? I've tried both but I can't figure out the correct syntax to do either, it seems.

I'll break it down in pseudo-code because that may be easier than actual code:

var query = new Parse.Query(Parse.User); query.find().then(function(users){

}).then(function(promisesArray){

// I would like "promisesArray" to either be the 2 arrays created in the preceding section, or a concatenation of them.

// Ultimately, I need a list of usernames here. Specifically, the users who had positive number values from the cloud functions in the preceding section

Questions: - At what point do I create & return promises & what syntax should I use for that? - Should .then(function(promisesArray){ be .when(function(promisesArray){ (when instead of then)?

Upvotes: 0

Views: 1037

Answers (3)

user3353762
user3353762

Reputation: 103

Thank you both for your ideas! This is what ultimately worked:

var query = new Parse.Query(Parse.User);
query.find().then(function(users){
  var allPromises = [];
  var promise1, promise2;

  _.each(users, function(user){
    if(user.get("myvalue") != "undefined" && user.get("myvalue") != ""){
      promise1 = Parse.Cloud.run("getBatch1", {param1: param1value, param2: param2value})
      .then(function(numResult){
        if(Number(numResult) > 0){
          return Parse.Promise.as(user.getUsername());
        }
      });
    }
    allPromises.push(promise1);

    if(user.get("anothervalue")==true){
      promise2 = Parse.Cloud.run("getBatch2", {param1: param1value, param2: param2value})
      .then(function(numResult2){
        if(Number(numResult2) > 0){
          return Parse.Promise.as(user.getUsername());
        }
      });
    }
    allPromises.push(promise2);
  });

  // Return when all promises have succeeded.
  return Parse.Promise.when(allPromises);

}).then(function(){
  var allPushes = [];
  _.each(arguments, function(pushUser){
    // Only add the user to the push array if it's a valid user & not already there.
    if(pushUser != null && allPushes.indexOf(pushUser) === -1){
      allPushes.push(pushUser);
    }      
  });

  // Send pushes to users who got new leads.
  if(allPushes.length > 0){
    Parse.Push.send({
      channels: allPushes,
      data: {
        alert: "You have new leads."
      }
    }, {
      success: function () {
        response.success("Leads updated and push notifications sent.");
      },
      error: function (error) {
        console.log(error);
        console.error(error);
        response.error(error.message);
      }
    });
  }
  response.success(JSON.stringify(allPushes));

}, // If the query was not successful, log the error
function(error){
  console.log(error);
  console.error(error);
  response.error(error.message);
});

Upvotes: 1

Jared Smith
Jared Smith

Reputation: 21926

First, you need to understand what Promises are. From what I understand of what you're trying to do it should look something like this:

//constructs the Parse Object
var query = new Parse.Query(Parse.User);

//find method returns a Promise
var res   = query.find()

//good names will be a Promise of an array of usernames
//whose value is above 0
var goodNames = res
    .then(function(data) {

        //assumes the find method returns an array of
        //objects, one of the properties is username
        //we will map over it to create an Array of promises
        //with the eventual results of calling the AJAX fn
        var numberPromises = data.map(function(obj) {

            //wrap the call to the cloud function in a new
            //promise
            return new Promise(resolve, reject) {
                someCloudFn(obj.username, function(err) {
                    if (err) {
                        reject(err);
                    } else {
                        resolve(num);
                    }
                });
            }
        };

        //Promise.all will take the array of promises of numbers
        //and return a promise of an array of results
        return [data, Promise.all(numberPromises)];
    })
    .then(function(arr) {

        //we only get here when all of the Promises from the
        //cloud function resolve
        var data    = arr[0];
        var numbers = arr[1];
        return data
            .filter(function(obj, i) {

                //filter out the objects whose username number
                //is zero or less
                return numbers[i] > 0;
            })
            .map(function(obj) {

                //get the username out of the query result obj
                return obj.username;
            });
    })
    .catch(function(err) {
        console.log(JSON.stringify(err));
    });

Now whenever you need to use the list of usernames whose number isn't zero you can call the then method of goodNames and get the result:

goodNames.then(function(listOfNames) {
    //do something with the names
});

Upvotes: 0

Shanoor
Shanoor

Reputation: 13662

I'm not familiar with Parse API but I'd do it this way. Of course, I can't test my code so tell me if it works or not:

var query = new Parse.Query(Parse.User);
query.find()
    .then(function(users) {
        var promises = [];
        users.forEach(function(user) {
            // the first API call return a promise so let's store it
            var promise = cloudFn1(user)
                .then(function(result) {
                    if (result > 0) {
                        // just a way to say 'ok, the promise is resolved, here's the user name'
                        return Parse.Promise.as(user.name);
                    } else {
                        // return another promise for that second API call
                        return cloudFn2(user).then(function(res) {
                            if (result > 0) {
                                return Parse.Promise.as(user.name);
                            }
                        });
                    }
                });

            // store this promise for this user
            promises.push(promise);
        });

        // return a promise that will be resolved when all promises for all users are resolved
        return Parse.Promise.when(promises);
    }).then(function(myUsers) {
        // remove duplicates is easy with _
        myUsers = _.uniq(myUsers);
        // do your push
        myUsers.forEach( function(user) {

        });
    });

Upvotes: 0

Related Questions