Ben Wheeler Ben Wheeler - 3 months ago 27
Javascript Question

What happens in a Parse Promise then block when execution reaches end of block before a return is encountered?

Suppose I have the following Parse cloud code:

// assume myObj is a parse object
myObj.set("field1", "foo");
Parse.Promise.as().then(function()
myObj.save(myObj, {
success: function(savedObj) {
// A
return Parse.Promise.as();
},
error: function(myObj, error) {
// B
return Parse.Promise.as();
}
});
// C
// note that we can get here without any return statement being called
}).then(function() {
// D
});


(Now, i know it would be simpler to just use promises for the whole thing:

myObj.save().then(
...


...but there are some functions that don't return promises, so sometimes you have no choice but to mix Backbone-style success/error blocks with promises.)

My question:

What happens when C is reached? Does execution pause on this promise until one of those return statements is reached, and then execution reaches D? Does execution advance directly to D after reaching C, without waiting for a return statement? Is this an error?

In other words, is it possible for execution to happen in the order C, D, A/B? Or will it always be C, A/B, D? (Or, I suppose, if save finishes crazy fast, something like A/B, C, D?)

Answer

Your returns are from the inner functions. If it was up to me I'd promisify the save function itself. However, if you're convinced you don't want to do this you still have to return a Parse.Promise from the then if you want it to wait for anything.

The then function returns a new promise and resolves that promise (executes further thens) when its return value is resolved. If that's just a value it will not wait for anything - if it's a promise it will wait for it in turn to resolve.

Please look at how to promisify for further reading.

In your example - this would look something like:

myObj.set("field1", "foo");
Parse.Promise.as().then(function(){
  var p = Parse.Promise();
  myObj.save(myObj, {
    success: p.resolve.bind(p), // on success, resolve the promise
    error: p.reject.bind(p) // on failure, reject it
  });
  // any code here _will_ execute before the `then` is called.
  return p; // return the promise so `then` will wait
}).then(function(savedObj) {
    // this will always run after `myObj.save` completed
    // you can add a catch handler for the error case
});

However, if we pay attention we can notice Parse's save method already returns a promise - Parse promisified it for us - so this code can be significantly reduced to:

myObj.set("field1", "foo");
Parse.Promise.as().then(function(){

  return myObj.save(myObj)
}).then(function(savedObj) {
  // this will always run after `myObj.save` completed
  // you can add a catch handler for the error case
});

Which in turn can be reduced to:

myObj.set("field1", "foo");
myObj.save().then(function(savedObj){
   // object save is done here
});