[heycam/webidl] Some things do not seem sound in “react to a Promise<T>” (#943)

In [react to a Promise<T> promise][1], which is the basis of the shorthand variants [upon fulfillment][2] and [upon rejection][3], the `onFulfilledSteps` begin:

1. Let `value` be the result of converting `V` to an IDL value of type `T`.
2. If there is a set of steps to be run if the promise was fulfilled, then let `result` be the result of performing them, given value if `T` is not `undefined`. Otherwise, let `result` be `value`.

Note that steps for handling fulfillment and rejection are both created regardless of whether there are “inner” steps that were supplied. The operation ends with `PerformPromiseThen(promise.[[Promise]], onFulfilled, onRejected, newCapability)` where these second and third args are the functions created from `onFulfilledSteps` and `onRejectedSteps`.

Two things surprised me here. The first is that `onRejectedSteps` won’t be invoked if conversion itself fails. Instead, the resulting `Promise<T>` will reject. In theory, a specification can still handle this scenario by subsequently reacting to that result promise, analogous to `promise.then(onF, onR).catch(onR)`. Almost all current usage of Promise as an input-from-ES type is `Promise<any>` or `Promise<undefined>`, where the distinction doesn’t matter because conversion never fails. But there is at least one spec where there’s an input `Promise` whose inner type’s conversion can fail — and that one spec ([Service Worker, `fetchEvent.respondWith`][4]) doesn’t appear to account for this. In fact, the first step in its “upon fulfillment” steps is this:

> If `response` is not a `Response` object, then set the `respond-with error flag`.

It seems like it would be impossible for `response` to ever not be a `Response` object here, since conversion would have thrown in step 1 of the `onFulfilledSteps` wrapper, and in Web IDL, unless ? or ! is used, I’m pretty sure the actual abrupt completion propagation is implicit, right? So if this were really implemented as written, `respondWith` would not actually handle this scenario — it doesn’t make use of the return value of its “upon fulfillment”, which is the promise that actually rejected due to conversion failure.

The second thing which seems odd to me is that a new conversion attempt is specified to occur for every reaction. So, looking at the same spec, there’s “upon fulfillment” and “upon rejection”, each of which use “react to”, and every “react to” has onFulfilled steps that begin with attempted conversion of the inner ES value to the inner Web IDL type. These conversions are observable to ES code and could produce different results at different times. I’m guessing this should really only happen (at most) once.

[1]: https://heycam.github.io/webidl/#dfn-perform-steps-once-promise-is-settled

[2]: https://heycam.github.io/webidl/#upon-fulfillment

[3]: https://heycam.github.io/webidl/#upon-rejection

[4]: https://w3c.github.io/ServiceWorker/#dom-fetchevent-respondwith


-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/heycam/webidl/issues/943

Received on Saturday, 5 December 2020 05:43:26 UTC