14

I want to know is there a difference between following two?

  1. aPromiseObj.then(fn1).then(fn2).catch(fn3);
  2. aPromiseObj.then(fn1); aPromiseObj.then(fn2); aPromiseObj.catch(fn3);

Will the work flow changed?

ps: I am in angular environment, though I would like to think this in a broader term.

Matt Tester
  • 4,663
  • 4
  • 29
  • 32
garyx
  • 609
  • 7
  • 19
  • 1
    Yes. The first method chains the promises while the second executes the `fn1`, `fn2` resolution handlers and `fn3` rejection handler on the same promise (`aPromise`). – Phil Aug 26 '15 at 01:33

1 Answers1

37

You have asked about "chaining" vs. "branching".

Assuming that f1 and f2 represent asynchronous operations that return promises, yes there is a significant difference. For option 1:

  1. It serializes fn1 and fn2 so that fn2 is not called until after the promise returned by fn1 has been resolved.
  2. .catch() applies to an error in either fn1 or fn2 or if aPromiseObj rejects.
  3. fn2 will not be called if fn1 rejects.

For option 2:

  1. fn2 does not wait for fn1 to resolve. fn2 is called as soon as fn1 returns similar to fn1(); fn2();. This means the async operations started by fn1 and fn2 will both be in-flight at the same time (sometimes referred to running in parallel instead of running serially).
  2. The .catch() does not apply to either because it is not on the promise that is created by either of the .then() calls. The .catch() in option 2, only applies to if aPromiseObj rejects, not f1() or f2().
  3. Both fn1 and fn2 will be called regardless of an error in either.

Another related question/answer: Understanding javascript promises; stacks and chaining

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • You say "For option 2: 1. It runs `fn1` and `fn2` in parallel, not in series". This is wrong; it executes `fn1` and `fn2` in series in both cases. The difference in control flow in absence of errors, as I understand it, is that in option 1, *if* fn1 returns a promise, fn2 won't run until that promise is fulfilled, and in that case fn2 will be passed the fulfilled value of the promise returned by fn1 (rather than the fulfilled value of aPromiseObj). – Don Hatch Oct 27 '16 at 10:19
  • @DonHatch - I clarified the wording. – jfriend00 Oct 27 '16 at 13:35
  • Thanks, it looks right to me now. – Don Hatch Oct 27 '16 at 15:04
  • I'd just add that in option 2, the `.catch()` block would be triggered if `aPromiseObj` throws. Also, the `then()` blocks would not trigger since `aPromiseObj` was not successful. – Sunny R Gupta Jul 20 '20 at 18:43
  • 1
    @SunnyRGupta - Thx, I updated the answer to include that point. – jfriend00 Jul 20 '20 at 21:49
  • Good answer, just ran into an issue / bug like this recently while fixing an angularjs app (the promise was branching and not chained), was not something I expected (or have tried to do) when you come from an angular 2+ background. Thanks – Johan Hendrik Ehlers Jun 02 '23 at 10:28