Michel
Michel

Reputation: 11753

How to make response.success() wait?

In the following Cloud function I need to know where and how to put the response.success() so that it gets executed once all the work is done and not before. I have already checked that the function is doing its job as expected. The only issue is the one I mentioned. I am trying to use Promises, but what I have done so far did not work.

 Parse.Cloud.define
 ("deleteUnitAndDependencies", function(request, response) {
    var unitListQuery;
    unitListQuery = new Parse.Query("UnitList");
    unitListQuery.equalTo("objectId", request.params.unitID);
    unitListQuery.equalTo("ownerID", request.params.userID);
    unitListQuery.find().then(function(resUnit) {
    var sentenceListQuery,sentenceListStatus;
    sentenceListQuery = new Parse.Query("SentenceList");
    sentenceListQuery.equalTo("unit", resUnit[0]);
    sentenceListStatus = sentenceListQuery.find();
    resUnit[0].destroy({});
    return sentenceListStatus;
    }).then(function(resSentence) {
    var translatListQuery,translatListQStatus;
    translatListQuery = new Parse.Query("TranslatList");
    for (iS = 0; iS < resSentence.length; iS++) {
        if (iS == 0 ) {
            translatListQuery.equalTo("sentence", resSentence[iS]);
            continue;
        }
        translatListQuery = Parse.Query.or(translatListQuery,
                                           (new Parse.Query("TranslatList")).equalTo
                                           ("sentence", resSentence[iS]));
    }
    translatListQStatus = translatListQuery.find();
    for (iS = 0; iS < resSentence.length; iS++) {
        resSentence[iS].destroy({});
    }
    return translatListQStatus;
    }).then(function(resTranslat) {
    for (iT = 0; iT < resTranslat.length; iT++) {
        resTranslat[iT].destroy({});
    }
    });
   });

Upvotes: 0

Views: 303

Answers (4)

Michel
Michel

Reputation: 11753

In case someone runs into similar issues, I put here the solution I came up with. It is working the way I want, as far as I have checked at this point. If some promise-expert reads this and has comments and suggestions to make it better please let us know.

Parse.Cloud.define
("deleteUnitAndDependencies", function(request, response) {
 var unitListQuery;
 unitListQuery = new Parse.Query("UnitList");
 unitListQuery.equalTo("objectId", request.params.unitID);
 unitListQuery.equalTo("ownerID", request.params.userID);

 unitListQuery.find().then
 (function(resUnit) {
  // If there is no UNIT we return an error.
  if (!resUnit.length) response.error("NO-UNIT");

  var sentenceListQuery;
  sentenceListQuery = new Parse.Query("SentenceList");
  sentenceListQuery.equalTo("unit", resUnit[0]);

  sentenceListQuery.find().then
  (function(resSentence) {
   var translatListQuery,tmpQuery;
   translatListQuery = new Parse.Query("TranslatList");

   for (iS = 0; iS < resSentence.length; iS++) {
    if (iS == 0 ) {
        translatListQuery.equalTo("sentence", resSentence[iS]);
        continue;
    }

    tmpQuery = new Parse.Query("TranslatList");
    tmpQuery.equalTo("sentence", resSentence[iS]);
    translatListQuery = Parse.Query.or(translatListQuery,tmpQuery);
   }

   translatListQuery.find().then
   (function(resTranslat) {
    var destroyPromises = [];
    for (iT = 0; iT < resTranslat.length; iT++) {
        destroyPromises.push(resTranslat[iT].destroy({}));
    }
    return Parse.Promise.when(destroyPromises);
    }).then
   (function() {
    var destroyPromises = [];
    for (iS = 0; iS < resSentence.length; iS++) {
        destroyPromises.push(resSentence[iS].destroy({}));
    }
    return Parse.Promise.when(destroyPromises);
    }).then
   (function() {
    return resUnit[0].destroy({});
    }).then(response.success);
   });
  });
 });

Upvotes: 0

Roamer-1888
Roamer-1888

Reputation: 19288

Michel, congratulations at getting it to work. That's no small achievement for someone who has been using promises for just a couple of days.

You will find that by creating a destroy() utility, you can avoid code repetition and compact the main routine right down.

With that utility and further simplifications/rearrangements, I ended up with this :

Parse.Cloud.define("deleteUnitAndDependencies", function(request, response) {
    //A utility function that gets called twice
    function destroy(arr) {
        return Parse.Promise.when(arr.map(function(r) {
            return r.destroy({});
        }));
    }
    var unitListQuery = new Parse.Query("UnitList");
    unitListQuery.equalTo("objectId", request.params.unitID);
    unitListQuery.equalTo("ownerID", request.params.userID);
    unitListQuery.find().then(function(resUnit) {
        var sentenceListQuery = new Parse.Query("SentenceList");
        sentenceListQuery.equalTo("unit", resUnit[0]);
        return sentenceListQuery.find().then(function(resSentence) {
            var translatListQuery = new Parse.Query("TranslatList");
            translatListQuery.equalTo("sentence", resSentence[0]);
            for (var iS = 1; iS < resSentence.length; iS++) {//loop counter now starts at 1
                translatListQuery = Parse.Query.or(translatListQuery, (new Parse.Query("TranslatList")).equalTo("sentence", resSentence[iS]));
            }
            return translatListQuery.find().then(destroy).then(function() {
                return destroy(resSentence.concat(resUnit[0]));
            });
        });
    }).then(response.success);
});

untested

Edit

As the destroys seem not to need to wait for each other, you should be able to do the .concat() trick twice, and call destroy() once.

return translatListQuery.find().then(function(resTranslat) {
    return destroy(resTranslat.concat(resSentence).concat(resUnit[0]));
});

Upvotes: 1

Timothy Walters
Timothy Walters

Reputation: 16874

There are multiple parts in your code that return promises. You need to include these in your promise chain. This is as simple as using a return statement.

This block for example:

    translatListQStatus = translatListQuery.find();
    for (iS = 0; iS < resSentence.length; iS++) {
        resSentence[iS].destroy({});
    }
    return translatListQStatus;
}).then(function(resTranslat) {
    for (iT = 0; iT < resTranslat.length; iT++) {
        resTranslat[iT].destroy({});
    }
});

You want to wait for those destroy calls to finish. Look at this section of the help on Promise Chaining in Parallel

    var findResults;
    translatListQStatus = translatListQuery.find()
    .then(function(resTranslat) {
        var destroyPromises = [];
        for (iS = 0; iS < resSentence.length; iS++) {
            destroyPromises.push(resSentence[iS].destroy({}));
        }

        // save these so we can return them at the end
        findResults = resTranslat;

        // return a promise here
        return Parse.Promise.when(destroyPromises);
    })
    .then(function() {
        // return the results we saved
        return findResults;
    });

    return translatListQStatus;
}).then(function(resTranslat) {
    var destroyPromises = [];
    for (iT = 0; iT < resTranslat.length; iT++) {
        destroyPromises.push(resTranslat[iT].destroy({}));
    }

    return Parse.Promise.when(destroyPromises);
});

Upvotes: 1

Farzher
Farzher

Reputation: 14563

Put a function into doSomeBigWork, when it's done with its async stuff, have it then call that function.

doSomeBigWork(function() {
    response.success();
});

Upvotes: 1

Related Questions