BlackMouse
BlackMouse

Reputation: 4552

Javascript Promises confusion

I'm trying to figure out Promises with Parse.

What I want to do is get a lot of jobs, and then perform an update for each job.

var queryJobs = new Parse.Query("Jobs");
queryJobs.find().then(function (results) {

    // Loop thorugh all jobs
    for (var i = 0; i < results.length; i++) {
        var job = results[i];

        // Here. I want to run an update on all object and then continue. 
    }

    return ????;

}).then(function () {
    status.success("Finish");
}, function () {
    status.error("Error");
});

I tried this without luck. The push block is never executed.

var queryJobs = new Parse.Query("Jobs");
queryJobs.find().then(function (results) {

    var promises = [];

    // Loop thorugh all jobs
    for (var i = 0; i < results.length; i++) {
        var job = results[i];


        promises.push((function () {

             // This is never executed. 

            var promise = new Parse.Promise();

            var query = new Parse.Query("Jobs");
            query.first({
                success: function (object) {
                    // ... Do something here.... 
                    promise.resolve();
                },
                error: function () {
                    promise.resolve();
                }
            });

            promise.resolve();
            return promise;
        }));
    }

    return Parse.Promise.when(promises);

}).then(function () {
    status.success("Finish");
}, function () {
    status.error("Error");
});

Thanks in advance

UPDATE

I've changed the code, and I get into the callback, however, the query is not executed.

        ...

        promises.push((function () {

            // GET HERE
            var promise = new Parse.Promise();

            var query = new Parse.Query("Jobs");
            query.first({
                success: function (object) {
                    console.log("CALLBACK");
                    promise.resolve();
                },
                error: function () {
                    console.log("CALLBACK");
                    promise.resolve();
                }
            });
        }()));

    return Parse.Promise.when(promises);

Upvotes: 0

Views: 411

Answers (2)

Jake T.
Jake T.

Reputation: 4378

Here is how I would set this up:

var failure = new Parse.Promise();
var success = new Parse.Promise();

var queryJobs = new Parse.Query("Jobs");
queryJobs.each
(
    function( job )
    {
        //Do your changes to the job
        return job.save().then
        (
            function( job )
            {
                return Parse.Promise.as( "job saved" );
            },
            function( error )
            {
                failure.reject("There was an error trying to save a job: " + error.message);
                return failure;
            }
        );
    }
).then
(
    function( results )
    {
        success.resolve("Successfully updated all the jobs" )
        return success;
    },
    function( error )
    {
        failure.reject("There was an error trying to query for Jobs: " + error.message);
        return failure;
    }
).then
(
    function( success )
    {
        response.success( success );
    },
    function( failure )
    {
        response.error( failiure );
    }
);

This may not work out of the box, but it has a few key features that may help you.

1) I know that one of the perks that is mentioned in the blog post and what not announces promises is that you can get rid of pyramid code, but if you want descriptive error messages, the pyramid code is a necessary evil. My first promise (queryJobs.each in this case) always has two .then()'s. The second one always just does response.error( failure ) and response.success( success ).

2) I create two promises, although you can use just one. I prefer two so it is clear where I'm failing / succeeding. I return these where I reach a dead end/ the finish line.

3) I used query.each instead of query.find. query.find() is limited to 1000 results, which, while it will probably be more than enough for a long time, will eventually cause you to hit your limit, and you'd need to start paginating your results. Using query.each will perform your function on every single object that could be returned by the query. One perk of query.each vs query.find and iterating through the results is that query.each performs it's callback on each object asynchronously, rather than a linear iteration.

4) In this case it would probably be better just to have return job.save() inside of the each block, but I wanted to show how I do the nested promise returns. This is what allows me to have very specific success / error statements. This is important because even if one link in your promise chain fails, you will keep executing the next links. The exception to this is if a promise is rejected and you don't have an error function until your last chain. The error will get passed from link to link until it finds an error function, which is fine, except it limits how much you can customize your error messages.

I'll also note that what you have is probably going to return the same object again and again for that query.first() method, rather than working with the specific job from the first query. Like, you are iterating through your jobs, but instead of doing anything with each job, you're getting the first job and doing something with it again and again. I don't think that's what you actually wanted, but maybe this is meant to be a "learn promises" post rather than something functional.

Anyway, hope I helped a bit. Let me know if you have questions and I'll do my best to answer them.

edit: I know my style varies greatly from others'. I like opening and closing brackets on a new line, for the most part. I actually read in javascript that this can sometimes cause errors. I forget the specific cases, but this is not one of them. But feel free to edit the style back to how you prefer it.

Upvotes: 2

Felix Kling
Felix Kling

Reputation: 816312

You have to add promises to promises, not functions. You need to call the function so that it returns the promise:

   promises.push((function () {
       // ...
   }()));
 // ^^

Furthermore you have to remove the promise.resolve(); call before the return statement. The promise should only be resolved after the query succeeded. As it currently is, the promise is resolved immediately.

Upvotes: 2

Related Questions