EthanSbbn EthanSbbn - 3 months ago 35
Node.js Question

Bluebird promises and catch branching

I'm wondering if there a way in Bluebird promises to

.catch
a thrown error and then process some specific actions without branching (nested promise).

Say I have

doSomethingAsync()
.then(function (result) {
if (!result)
throw new CustomError('Blah Blah');

if (result == 0)
throw new CustomError2('Blah Blah Blah');

return result;
})
.then(function (result) {
console.log('Success, great!');
})

.catch(CustomError, function (error) {
// Oh CustomError!
return saveSomethingAsync();
})
.then(function (saved) {
// Should only be executed if an CustomError has been thrown
console.log("Let's try again");
return doSomethingAsync();
})

.catch(CustomError2, function (error) {
// Oh CustomError2!
})
.delay(15000) // Don't try again now !
.then(function () {
// Should only be executed if an CustomError2 has been thrown
console.log("Let's try again after some long delay");
return doSomethingAsync();
})

.catch(function (error) {
// Should catch all random errors of the chain
})


When I execute this code, I get several behaviours:


  • If no error throws, I get "Success, great!" and it start again with "Let's try again after some long delay"

  • If CustomError throws, I get "Let's try again"

  • If CustomError2 throws, I get "Let's try again after some long delay"



I can't figure out what's happening with this flow.
Should be great to write something like this instead of nesting the errors' specific code in new promise chains.

Answer

.catch a thrown error and then process some specific actions without branching

No. Because that is branching. Nesting is totally natural here. You could even think of this using the synchronous-try-catch metaphor and it would be the same.

I can't figure out what's happening with this flow.

  • If no error is thrown, I get "Success, great!" and it start again with "Let's try again after some long delay"

Hm, that's odd, because the "Let's try again" (without delay) is chained before that. You should eventually get both logs. Your chain is processed sequentially:

doSomethingAsync() // returns a result
 then return result // first callback: continues with it
 then console.log('Success, great!') // next callback: logs something
 catch // is ignored because no rejection
 then console.log("Let's try again"); // next callback: logs something
      return doSomethingAsync();      //                and returns a result
 catch // that result, not being a rejection, is ignored here
 delay // fulfillment is delayed
 then console.log("Let's try again after some long delay"); // next callback again logs
      return doSomethingAsync();                            // and returns a result
 catch // is ignored again
  • If a CustomError is thrown, I get "Let's try again"

Yes, because saveSomethingAsync();, the result of the previous promise, is fulfilled, so the next .then() callback in the chain executes.

  • If a CustomError2 is thrown, I get "Let's try again after some long delay"

Yes, because the error bubbled all the way down to .catch(CustomError2, …) where it was eventually handled. On its way, no callbacks were executed. After the error was handled, the promise is fulfilled, and the next .then() in the chain calls its callback.

I think what you really want here is

doSomethingAsync()
.then(function(result) {
  if (!result)
    // CustomError('Blah Blah');
    // Oh CustomError!
    return saveSomethingAsync();
    .then(function(saved) {
      console.log("Let's try again");
      return doSomethingAsync();
    });
  else if (result == 0)
    // CustomError2('Blah Blah Blah');
    // Oh CustomError2!
    return Promise.delay(15000) // Don't try again now !
    .then(function() {
      console.log("Let's try again after some long delay");
      return doSomethingAsync();
    })
  else
    console.log('Success, great!');
  // return undefined implied
}).catch(function (error) {
  // does catch all random errors of the chain
  // thrown by any of the doSomethingAsync() or of the saveSomethingAsync
})
Comments