ai20 ai20 - 4 months ago 24
AngularJS Question

Javascript then promise not sequential with Parse queries in for loop

I wrote a sequence of functions which include Parse queries:

var query1 = new Parse.Query(Events);
query1.equalTo("id_organizer", $localStorage.username);
query1.greaterThanOrEqualTo("date_start",currentTime)
query1.each(function(results){
var object = results;
eventname = object.get("event_name");
datestart = object.get("date_start");
location = object.get("location");
id_event = object.get("id_event")
eventimagefile = object.get("event_image");
eventimageurl = eventimagefile.url();
description = object.get("description");
id_organizer = object.get("id_organizer");
min_twitter_followers = object.get("min_twitter_followers");
min_instagram_followers = object.get("min_instagram_followers");
min_facebook_friends = object.get("min_facebook_friends");
max_number_requests = object.get("max_number_requests");
eventDetails.push({'name':eventname,'location':location, 'datestart':datestart, 'eventphoto':eventimageurl,'organizer':id_organizer, 'description':description, 'minTwitterFollowers':min_twitter_followers, 'minFacebookFriends':min_facebook_friends, 'minInstagramFollowers':min_instagram_followers,'maxNumberRequests':max_number_requests, 'id_event':id_event})
}).then(function(){

alert("start")

var Attendees = Parse.Object.extend("Attendees");
eventDetails.forEach(function(e){
var query2 = new Parse.Query(Attendees);
query2.equalTo("event_id", e.id_event);
query2.count({
success: function(number) {
e["n_requests_received"] = number;
alert("received")
}
})

var query3 = new Parse.Query(Attendees);
query3.equalTo("event_id", e.id_event);
query3.equalTo("status", "confirmed")
query3.count({
success: function(number) {
e["n_requests_confirmed"] = number;
// alert("confirmed")
}
})
})

}).then(function(){
alert("end")
alert(JSON.stringify(eventDetails))
$scope.events = eventDetails;
$localStorage.events = eventDetails;
});
})


unfortunately the alert "end" is printed right after "start" without waiting for the queries (query1,query2) inside the foreach loop to be executed. Do you know how I can make the for loop with the 2 queries executed before the next then?

Answer
.then(function(){ 
        alert("start")
        var Attendees = Parse.Object.extend("Attendees");

        return Promise.all(eventDetails.map(detail => {
            return Promise.all([new Promise((res, rej) => {
                var query2 = new Parse.Query(Attendees);
                query2.equalTo("event_id", detail .id_event);    
                query2.count({
                    success: function(number) {
                        e["n_requests_received"] =  number;
                        alert("received")
                        res('Some value if required'); //These are needed or promise chain will hang
                    }
                });
            }),
            new Promise((res, rej) => {
                var query3 = new Parse.Query(Attendees);
                query3.equalTo("event_id", detail .id_event);
                query3.equalTo("status", "confirmed")
                query3.count({
                    success: function(number) {
                        e["n_requests_confirmed"] =  number;
                       // alert("confirmed")
                       res('Some value if required'); //These are needed or promise chain will hang
                    }
                });
            })]);
        }));
})

Promise chains will wait for promises. That is if a .then anywhere in the chain receives an unresolved promise it will wait for that promise to resolve.

So what you could do is use Promise.all which expects an array of promises and will resolve when they do. So map over your array eventDetails creating a promise from each cell. Inside each cell use another Promise.all to create two new promises for both of your Query objects.

This way your .then will wait for your eventDetails array of promises to resolve. Then each cell in eventDetails will wait for your array of queries to resolve.

NOTE: The new Promise() where we are creating promises. It passes you two callbacks to resolve or reject the promise. This is how you wrap old callback style API's in a promise. However if you do not call either of them to resolve or reject then the whole promise chain could hang (depending on its design) waiting for that promise to resolve.

Hope that makes sense. This is pseudo code but you should get the idea.


Disclaimer i have not used Parse.Query i do not know what it is. However this method is how i would handle the above program flow of using an old callback style API, where you essentially have nested loops.


Extra Disclaimer: My example is using ES6 syntax. Not all browsers (IE) support that yet.

Comments