4

Why doesn't Promise.prototype.finally() receive any arguments?

The documentation says:

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

However, i can add a simple method to the Promise prototype, lets name it finally2 (Promise.prototype.finally2) which can receive the result, and can reliably determine if the promise was fulfilled or rejected.

Promise.prototype.finally2 = function(callback){
    return this.then(result => callback(result), result => callback(undefined, result));
}

I understand (as the documentation says) that the use case for Promise.prototype.finally is precisely when you do not care about the rejection reason, or the fulfillment value.

My question is: How is it unreliable to determine if the promise was fulfilled or rejected in Promise.prototype.finally?

Promise.prototype.finally2 = function(callback){
 return this.then(result => callback(result), result => callback(undefined, result));
}

Promise.resolve(2).finally((...args) => console.log('finally:resolve =>', args));
Promise.reject(2).finally((...args) => console.log('finally:reject =>', args));

Promise.resolve(2).finally2((...args) => console.log('finally2:resolve =>', args));
Promise.reject(2).finally2((...args) => console.log('finally2:reject =>', args));
McKabue
  • 2,076
  • 1
  • 19
  • 34
  • 2
    Frankly, if you want to act in a specific way if it was fulfilled, then use `.then()` and to act a specific way if it was rejected, then use `.catch()`. Use `.finally()` ONLY when you don't need to know, you just want to know that the promise is done, no matter which way it finished. I think the authors probably also wanted to prevent people putting resolve-only code or reject-only code in a finally because it doesn't belong there. Note, the return value of `.finally()` behaves differently than `.then()` or `.catch()`. It is for a completely different purpose. – jfriend00 Sep 15 '19 at 07:29
  • 1
    Also, just because you can create your own `.finally2()` hack does not mean it's a good idea to code that way. Also, your `.finally2()` does not follow the `.finally()` specification for the promise that it returns. Remember, code in a `.finally()` does not affect the resolved/rejected value of the promise that the `.finally()` call returns. That was already determined before the `.finally()` handler ran by what happened to the parent promise. – jfriend00 Sep 15 '19 at 07:39
  • 2
    @jfriend00 Your argument is correct as it is justified, but it doesn't answer the question... not all questions on StackOverflow are a `bug` or `something not working`... some are meant for learning... and i want to learn... For clarity, my questions is: **How is it unreliable to determine if the promise was fulfilled or rejected in `Promise.prototype.finally`?** – McKabue Sep 15 '19 at 08:21
  • the way I look at it, consider that `.then` callbacks, and `.catch` callback receive a single argument - following this pattern, if `.finally` callback received a single argument, how would you know if the promise was fulfilled or rejected? – Jaromanda X Sep 15 '19 at 08:23
  • 1
    @McKabue - I'm not even sure it is unreliable - just undesirable (from a cleanliness of coding and design point of view). That's just something written on MDN. That's a community edited site for developers, not always the absolute truth. The real answers to "why" it wasn't given an argument are in the heads of the developers who participated in the `.finally()` design. There's probably chatter about that design in the history of some standard's body mailing list. – jfriend00 Sep 15 '19 at 08:25
  • Check this answer: https://stackoverflow.com/a/42028776/1243247 – João Pimentel Ferreira Jan 27 '23 at 08:55

2 Answers2

0

It is possible to reliable determine whether a promise was fulfilled or rejected, using .then(…, …). Your implementation shows that (although it is unfaithful about the return value, compare the native finally resolving to the original result when the callback doesn't throw).

But you're right, the reasoning of the section you quoted is garbage. And indeed, in the years since your question, MDN has been updated and now only says

The onFinally callback does not receive any argument. 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.

That's really all there is to say. The finally method is used when you do not care about the outcome of the promise, just like a finally block on a try. If you did care, you wouldn't (shouldn't) use finally in the first place.

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

The only way I see to solve this is to use an external function

someAsyncCallWithPromise(param)
   .then((res) => {
      // do something with res
      finally(null, res)
   })
   .catch((err) => {
      // handle the error
      finally(err)
   })

function finally(err, res) {
  if (err) {
     console.error('Concluded with error', err)
  } else {
     // do something final with res
  }
}
João Pimentel Ferreira
  • 14,289
  • 10
  • 80
  • 109