tc39 / proposal-mass-proxy-revocation

Proposal for revoking proxies en masse.
MIT License
5 stars 1 forks source link

A more minimal version #8

Closed Jack-Works closed 2 years ago

Jack-Works commented 2 years ago

TLDR:

We don't add signals into the language.

Details:

Add an internal slot:

[[RevocationSignal]]: Record { revoked: boolean, callbacks: list of Abstract Closure }

These callbacks should be synchronously invoked.

  1. Host object AbortSignal is having this slot.
  2. new Proxy:
    1. Let signal be options?.signal
    2. If signal does not have a [[RevocationSignal]] internal slot, throw a TypeError.
    3. Let revocable be %Proxy.revocable%(target, handler)
    4. Let revokeFunction be revocable.revoke
    5. Let closure be a new Abstract Closure that captures revokeFunction with the following steps:
      1. Call revokeFunction()
    6. Push closure to signal.[[RevocationSignal]].callbacks
    7. Return revocable.proxy
ajvincent commented 2 years ago

I have questions. Also, the recording of today's SES meeting isn't up yet, so I might mis-remember this. Please be understanding that I lack some understanding / context myself as I write this.

https://tc39.es/ecma262/#sec-proxycreate 10.5.14 https://tc39.es/ecma262/#sec-proxy-objects 28.2

Jack-Works commented 2 years ago

API shape is not important here. My given spec is very informal, just used to express the idea of, we can use the AbortSignal in the language even we don't add it into the language.

The core idea here is to define a "protocol" to take the host AbortSignal for our usage. It is a bit like [[IsHTMLDDA]], no object defined in the language has this field, but the host can define one.

Once AbortSignal has the [[RevocationSignal]] field we need, it can be used as the signal we want in this proposal.

Particularly since an array of revoker functions (each of which holds a strong reference to the proxy in the internal slot, which is a separate memory-leak issue I've discussed elsewhere) is about as expensive as the current proxy model

If the optimized version (a flag in the memory) does not have an observable difference, the engine can optimize it.

An example of this is Map.prototype.has: https://tc39.es/ecma262/multipage/keyed-collections.html#sec-map.prototype.has

It use a O(N) algrithm to check if an element is present in the map, but since it does not have an observable difference (other than the performance), most engine will use a hash map instead. The spec is just make it easier to read.