This is intentional - `catch` delegates to `then`, so that a subclass that
overwrites `then` doesn't have to also override `catch` (and the same for
`finally`, which also calls into `then`).

On Fri, Jul 20, 2018 at 4:29 AM, Darien Valentine <valentin...@gmail.com>
wrote:

> In `Promise.prototype.then`:
>
> > 1. Let promise be the this value.
> > 2. If IsPromise(promise) is false, throw a TypeError exception.
> > [ ... ]
>
> In `Promise.prototype.finally`:
>
> > 1. Let promise be the this value.
> > 2. If Type(promise) is not Object, throw a TypeError exception.
> > [...]
>
> In `Promise.prototype.catch`:
>
> > 1. Let promise be the this value.
> > 2. Return ? Invoke(promise, "then", « undefined, onRejected »).
>
> First, this means that only `then` requires the this value to be a Promise:
>
> ```js
> for (const key of [ 'then', 'finally', 'catch' ]) {
>   try {
>     Promise.prototype[key].call({
>       then: () => console.log(`${ key } doesn’t brand check its this
> value`)
>     });
>   } catch (err) {
>     console.log(`${ key } does brand check its this value`);
>   }
> }
>
> // > then does brand check its this value
> // > finally doesn’t brand check its this value
> // > catch doesn’t brand check its this value
> ```
>
> Second, note that `Invoke` uses `GetV`, not `Get`. Thus:
>
> ```js
> for (const key of [ 'then', 'finally', 'catch' ]) {
>   try {
>     String.prototype.then = () =>
>       console.log(`${ key } casts this value to object`);
>
>     Promise.prototype[key].call('foo');
>   } catch (err) {
>     console.log(`${ key } doesn’t cast this value to object`);
>   }
> }
>
> // > then doesn’t cast this value to object
> // > finally doesn’t cast this value to object
> // > catch casts this value to object
> ```
>
> On reflection, I think I see the logic to this:
>
> - `Promise.prototype.then` ends up executing `PerformPromiseThen`, which
> requires its first argument to be a native promise object.
> - `Promise.prototype.finally` ends up executing `SpeciesConstructor`,
> which requires its first argument to be an object.
> - `Promise.prototype.catch` does neither.
>
> However the inconsistency within this trio seems pretty odd to me. I
> suppose I would have expected them all to be as constrained as the most
> constrained method needed to be for the sake of uniformity, given that they
> constitute a single API. Conversely, if the goal was for each method to be
> exactly as lenient as is possible, then `finally` seems to be
> over-constrained; it seems like `C` could have just defaulted to `Promise`
> in cases where `SpeciesConstructor` wasn’t applicable, making it as lenient
> as `catch`.
>
> I wasn’t able to find prior discussion about this, though it’s a bit hard
> to search for, so I may be missing it. Do these behaviors seem odd to
> anyone else, or is it what you’d expect?
>
> _______________________________________________
> es-discuss mailing list
> es-discuss@mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
>
_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to