Skip to content

a potential unobservable check for fast-path #1

@bakkot

Description

@bakkot

Copying from the matrix:

If your fast path is guarded on IsPromise(p) && GetOwnProperty(p, 'then') == undefined && GetPrototypeOf(p) == %Promise.prototype%, that never runs user code (because the IsPromise(p) check rules out proxies, which means the other two checks are unobservable).

This is slightly different from the existing fast-path in PromiseResolve, but that could probably changed to match this; it's getting at the same concept. There should be very few things for which these two tests differ.


EDIT: Per below I think we actually want IsPromise(p) && GetPrototypeOf(p) === C.prototype, where C is the built-in %Promise% in every case except in the actual static .resolve() method (in which case it's the class on which .resolve was invoked). This has the advantage of preserving current behavior (except for the .constructor lookup) when calling PromiseSubclass.resolve(). And it's still unobservable for any actual await, and for the built-in promise resolution functions created by the Promise constructor, because in those cases C will be the native Promise, and the .prototype property of the native Promise is nonwritable/nonconfigurable.

This is very close to the current check in PromiseResolve, which is IsPromise(p) && p.constructor === C, except that it's unobservable (except in the DerivedPromise.resolve() case). So it's unlikely to break anything, even subclasses of Promise.

Specifically, this keeps the same behavior for

  • regular new Promise promises (fast path)
  • new Promise promises which have been patched with a custom .then (fast path)
  • instances of Promise subclasses using class extends Promise (no fast path)
  • thenable objects which do not inherit from Promise, unless they've manually set .constructor = Promise in which case they probably were broken (no fast path)
  • thenable objects which manually inherit from Promise as in { __proto__: Promise.prototype } (no fast path)

It changes behavior for

  • new Promise promises which had their .constructor manually changed away from Promise (previously not fast path, now fast path)
  • instances of Promise subclasses using class extends Promise which had their .constructor manually changed to Promise (previously fast path, now not fast path)

The change in behavior is just whether accessors on .constructor are triggered and whether some object gets the fast path in cases where people were manually changing the .constructor. I strongly suspect these changes would be web compatible.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions