3

I'd like to do something like this:

return1stPromise()
  .then(if1stPromiseSucceeds) // returns 2nd Promise
  .catch(if1stPromiseFails)
  .then(if2ndPromiseSucceeds) // execute only if 1st Promise succeeds

I'd like the 2nd .then to execute only if 1st Promise succeeds. Or in different words - I don't want the 2nd .then to execute if the catch has been executed.

Is this even possible or do I have nest the 2nd promise inside the first then like this:

return1stPromise()
  .then(function (data) {
    return if1stPromiseSucceeds(data).then(if2ndPromiseSucceeds);
  })
  .catch(if1stPromiseFails);

In addition - any good resources on how to control flow with Promises where it's more thread like?

krulik
  • 976
  • 1
  • 10
  • 31
  • 1
    Your `catch` will be called if any of the promises in the chain fail, not only the first. Can you be more specific about what you'd like to happen? – timothyclifford Aug 28 '16 at 12:06
  • "Is this even possible". Yes it is. What you have posted will work that way. – Ram Aug 28 '16 at 12:06
  • I'm sorry I wasn't clear enough: I'd like the 2nd `.then` to execute only if 1st Promise succeeds. Or in different words - I don't want the 2nd `.then` to execute if the `catch` has been executed. Updated question. – krulik Aug 28 '16 at 12:09
  • @krulik: Well, that changes the question significantly. – T.J. Crowder Aug 28 '16 at 12:10
  • 1
    I believe what you actually want is `return1stPromise().then(x => if1stPromiseSucceeds(x).then(if2ndPromiseSucceeds), if1stPromiseFails)`. Have a look [here](http://stackoverflow.com/q/24662289/1048572) about the difference. – Bergi Aug 28 '16 at 12:58

2 Answers2

3

What you are describing is typically the case when we want to react to an exception but not actually handle it and let the code keep running:

return1stPromise()
  .then(if1stPromiseSucceeds) // returns 2nd Promise
  .catch(() => { if1stPromiseFails(); throw e; })
  .then(if2ndPromiseSucceeds) // execute only if 1st Promise succeeds

You need to rethrow the exception in order to mark it as "still not handled".

This is like synchronous code:

try {
  var res = firstResult();
  var res2 = ifFirstPromiseSucceeds(res);
} catch (e) {
    ifFirstPromiseFails();
    throw e; // we reacted to the exception but did not handle it yet.
}
var res3 = ifSecondPromiseSucceeds();

I think thinking of promises in terms of threads is mostly confusing - finding a synchronous analogy is always easier if possible.

It's not always possible, for example another way to stop a promise chain in the way is cancellation which is a little like a thread abort with "I don't care about the results" semantics - you can read about it here but I think for your use case it's a little over the top and not as nice.

Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
1

I would probably do throws and catches but if you don't want to do, you can always return a rejected promise to bypass the next then stage. Such as;

new Promise((resolve,reject) => { var rnd = Math.random();
                               rnd > 0.5 ? resolve(21)
                                         : reject("promise error");
                                })
    .then(val  => { var rnd = Math.random();
                    if (rnd < 0.5) return Promise.reject("then error");
                    return Promise.resolve(val*2);
                  })
    .catch(err => { console.log(err);
                    return Promise.reject("you won't see this");
                  })
    .then(val  => console.log("Both the promise and the first then stage worked fine and resulted: ", val));

The last then stage callback will only be invoked if the first promise and the second promise at the first then stage resolves.

Redu
  • 25,060
  • 6
  • 56
  • 76