I am learning a bit about promises in Javascript and am wondering if there is any difference when reordering in the following way <...>.get().then().then().catch().finally()
vs <...>.get().then().catch().then().finally()
?
-
1What do you think will happen if the code in the first `then` throws/rejects in both cases? – t.niese Feb 27 '22 at 11:59
2 Answers
With the following chain
<...>.get().then().then().catch().finally()
catch
method will handle the rejection of all the previous promises in the chain, whereas with the following chain
<...>.get().then().catch().then().finally()
catch
method will not handle the rejection of promise returned by the last then
method.
This kind of chain is useful when you want to handle a promise rejection and turn it into fulfilment of the promise returned by the catch
method to allow the promise chain to continue.
If the resulting promise of the 2nd chain is used somewhere or if you are returning the promise at the end of this chain from a function as shown below,
function foo() {
return <...>.get().then().then().catch().finally();
}
then not using another catch
method is fine because in that case, the code that calls this function can handle the promise rejection that wasn't caught and handled by the promise chain itself.
However, if that's not the case, then you should definitely have a 2nd catch
method after the last then
method call as well.

- 27,861
- 6
- 44
- 69
-
1`However, in the 2nd chain, you should definitely have a 2nd catch method after the last then method call as well.` That would only be true if the Promise returned at the end of the chain isn't used somewhere else, e.g. returned from a function (It might perfectly valid that the caller of the function has to handle the error.) – t.niese Feb 27 '22 at 12:07
-
1
Yes, they are different.
Let's say you have this:
<...>.get().then(() => A()).then(() => B()).catch(() => ErrorHandling()).finally(() => D())
<...>.then(() => A()).catch(() => ErrorHandling()).then(() => B()).finally(() => D())
You could translate this to an await
/async
representation:
// <...>.get().then(() => A()).then(() => B()).catch(() => ErrorHandling()).finally(() => D())
try {
await get();
await A();
await B();
} catch( ) {
await ErrorHandling()
} finally {
await D();
}
// <...>.then(() => A()).catch(() => ErrorHandling()).then(() => B()).finally(() => D())
try {
try {
await get();
await A();
} catch( ) {
await ErrorHandling()
}
await B();
} finally {
await D();
}
In the first case, B
won't be executed if either get
or A
results in an error. In the second case B
will be executed even if get
or A
results in an error, the only case where it won't be executed is if ErrorHandling
results in an error.
So the first one is used if B
depends on get
and A
to be successfully executed. The second case is used e.g. if B
should do some thing not matter if get
or A
was succesfull.

- 39,256
- 9
- 74
- 101