2

I'm writing a background job function on Parse.com CloudCode. The job needs to call the same function (that includes a Parse.Query.each()call) several times with different parameters, and I want to chain these calls with promises. Here's what I have so far:

Parse.Cloud.job("threadAutoReminders", function(request, response) {

    processThreads(parameters1).then(function() {
        return processThreads(parameters2);
    }).then(function() {
        return processThreads(parameters3);
    }).then(function() {
        return processThreads(parameters4);
    }).then(function() {
        response.success("Success");
    }, function(error) {
        response.error(JSON.stringify(error));
    });
});

Below is the processThreads() function:

function processThreads(parameters) {

    var threadQuery = new Parse.Query("Thread");
    threadQuery... // set up query using parameters

    return threadQuery.each(function(thread) {
        console.log("Hello");
        // do something
    });
}

My questions are:

  • Am I chaining function calls using promises correctly?
  • What happens in threadQuery.each() returns zero results? Will the promise chain continue with execution? I'm asking because at the moment "Hello" never gets logged..
artooras
  • 6,315
  • 9
  • 45
  • 78
  • Does `each()` return a promise? What does its callback do? – Bergi Nov 10 '15 at 16:47
  • `each()` returns nothing, it just updates an object and stores it in an array. – artooras Nov 10 '15 at 16:50
  • Is there anything asynchronous in `processThreads` at all? – Bergi Nov 10 '15 at 16:54
  • Then there is no reason to use promises either. Just call the function multiple times, synchronously, without any `then` chaining. – Bergi Nov 10 '15 at 17:05
  • How about the `each()` functions? I will have several of them running concurrently, right? (a) Is there no limitation on concurrent processes in Parse background job? (b) Is it OK for several threads to be writing to the same array at the same time? – artooras Nov 10 '15 at 17:18
  • Well you said they weren't asynchronous, so they shouldn't be running concurrently either. – Bergi Nov 10 '15 at 17:18
  • Aside from the obvious `each()` call, which is asynchronous, there are no more asynchronous calls - sorry I didn't point that out. In case I _would_ need to use promises, is my chaining correct? – artooras Nov 10 '15 at 17:47
  • Yes, your `then` chaining is correct. Only if `each` is asynchronous, and does not return anything, you'll need to find a way to detect when it has finished its asynchronous execution, and then return a promise for that. – Bergi Nov 10 '15 at 17:55
  • The value that returns `processThreads` will be passed to the next `then`. In this case, you passed `undefined` because `each`, as you have said, returns nothing. You can create a promise in `processThreads` then *reject* or `resolve` it and at lastly, after you `each`, return this promise. – Victor Aguilar Nov 10 '15 at 19:28
  • @Pollin, would you mind creating an answer with sample code to illustrate your suggestion? – artooras Nov 10 '15 at 19:31
  • Artooras, is "do something" `doSomethingSynchronous() ` or `doSomethingAsynchronous() `? – Roamer-1888 Nov 10 '15 at 22:25
  • "do something" is synchronous – artooras Nov 11 '15 at 05:55

2 Answers2

2

Am I chaining function calls using promises correctly?

Yes.

What happens in threadQuery.each() returns zero results? Will the promise chain continue with execution? I'm asking because at the moment "Hello" never gets logged.

I think I'm right in saying that, if "do something" is synchronous, then zero "Hello" messages can only happen if :

  • an uncaught error occurs in "do something" before a would-be "Hello" is logged, or
  • every stage gives no results (suspect your data, your query or your expectation).

You can immunise yourself against uncaught errors by catching them. As Parse promises are not throw-safe, you need to catch them manually :

function processThreads(parameters) {
    var threadQuery = new Parse.Query("Thread");
    threadQuery... // set up query using parameters
    return threadQuery.each(function(thread) {
        console.log("Hello");
        try {
            doSomething(); // synchronous
        } catch(e) {
            //do nothing
        }
    });
}

That should ensure that the iteration continues and that a fulfilled promise is returned.

Roamer-1888
  • 19,138
  • 5
  • 33
  • 44
  • The problem I see with this, based on my code logs, is that nothing inside the `each()` callback gets called if there are no threads found – artooras Nov 11 '15 at 07:53
  • Yes, highly likely. Eliminate the other possibility by running with no "doSomething", just `console.log("Hello");`. – Roamer-1888 Nov 11 '15 at 10:11
1

The following example shows as use promises inside your function using a web browser implementation.

function processThreads(parameters) {

    var promise = new Promise();
    var threadQuery = new Parse.Query("Thread");
    threadQuery... // set up query using parameters

    try {
        threadQuery.each(function(thread) {
            console.log("Hello");
            if (condition) {
                throw "Something was wrong with the thread with id " + thread.id;
            }
        });
    } catch (e) {
        promise.reject(e);

        return promise;
    }

    promise.resolve();

    return promise;
}

Implementations of promise:

Web Browser https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

jQuery https://api.jquery.com/promise/

Angular https://docs.angularjs.org/api/ng/service/$q

Victor Aguilar
  • 455
  • 4
  • 18