-1

Before ES2018, I used to nest an extra then at the end of the promise chain whenever I had to perform any clean up logic that I'd otherwise duplicate in then and catch above, e.g.

new Promise(
  (res, rej) => setTimeout(() => rej({}), 1000)
).then(
  res => console.log(res)
).catch(
  err => console.error(err)
).then(
  () => console.log('Finally')
)

But now that finally was added on the Promise prototype, I can't see how it's different from the last then in the above approach. The following will produce identical output.

new Promise(
  (res, rej) => setTimeout(() => rej({}), 1000)
).then(
  res => console.log(res)
).catch(
  err => console.error(err)
).finally(
  () => console.log('Finally')
)

Does finally merely serve a semantic purpose in the native Promise API?

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
Alex
  • 3,719
  • 7
  • 35
  • 57
  • 2
    https://stackoverflow.com/questions/41130154/what-is-the-difference-between-then-and-finally-in-a-promise – epascarello Apr 16 '18 at 19:00
  • @epascarello That one is about Bluebird – Alex Apr 16 '18 at 19:00
  • 1
    It is all basically the same thing – epascarello Apr 16 '18 at 19:05
  • The differences are literally listed in [the docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally#Description). They're not quite the same. – Herohtar Apr 16 '18 at 19:11
  • @Herohtar Sure, but the docs contrast it with `.then(() => {}, () => {})`. I'm talking about `.then(() => {}).catch(() => {}).then(() => {})` – Alex Apr 16 '18 at 19:14

2 Answers2

5

A then callback doesn't execute when the promise is rejected - and that can happen even for a promise returned by a catch invocation: when its callback throws or returns a rejected promise. err => console.error(err) is probably not going to do that, but you never know.

Similarly, I would recommend to favour .then(…, …) over .then(…).catch(…) if you only want to handle errors from the original promise, not from the then callback. I'd write

promise.then(console.log, console.error).finally(() => console.log('Finally'));

The other more or less obvious differences are in the signature: the finally callback doesn't receive any arguments, and the promise that p.finally() returns will fulfill/reject with the same result as p (unless there's an exception or returned rejection in the callback).

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
1

finally() executes whether the promise is fulfilled or rejected. Maybe the MDN doc's example will help.

Edit: the MDN doc gives these differences from then():

The finally() method is very similar to calling .then(onFinally, onFinally) however there are couple of differences:

  • When creating a function inline, you can pass it once, instead of being forced to either declare it twice, or create a variable for it
  • A finally callback will not receive any argument, since there's no reliable means of determining if the promise was fulfilled or rejected. This use case is for precisely when you do not care about the rejection reason, or the fulfillment value, and so there's no need to provide it.
  • Unlike Promise.resolve(2).then(() => {}, () => {}) (which will be resolved with undefined), Promise.resolve(2).finally(() => {}) will be resolved with 2.
  • Similarly, unlike Promise.reject(3).then(() => {}, () => {}) (which will be fulfilled with undefined), Promise.reject(3).finally(() => {}) will be rejected with 3.
Herohtar
  • 5,347
  • 4
  • 31
  • 41
hhoburg
  • 373
  • 2
  • 10