Champion group: Daniel Ehrenberg, Yulia Startsev
FinalizationRegistry.prototype.cleanupSome method was originally part of the TC39 Proposal for
WeakRefs. This method provided a way for library authors to synchronously allow them to clean up without yielding to the event loop. We propose to move it into a separate proposal, to allow the core of WeakRefs to be used in the wild a bit before adding this additional functionality.
Motivation of cleanupSome
In HTML, the granularity is based on tasks and microtasks: WeakRefs are only allowed to observably go from "filled with an object" to undefined at the end of a microtask checkpoint (i.e., after all the Promise jobs run), and FinalizationRegistry cleanup callbacks happen in a queued task, meaning also only when all the Promise jobs have run. This all adds up to: you need to yield to the event loop regularly to make WeakRef and FinalizationRegistry work.
This use case is met by
FinalizationRegistry.prototype.cleanupSome. It accepts a function as a parameter (or can fall back to the
FinalizationRegistry's callback), and may call that callback with the
heldValue of any registered, garbage-collected value, to synchronously perform cleanup actions.
Hesitation: When should
cleanupSome be exposed on the Web?
The "long job" case doesn't quite make sense on the "window", the Web's main thread. It makes more sense for background Worker/Worklet threads. So, in browsers, it may make sense to exclude it from the window. There are several other Web Platform APIs which are only exposed in the context of certain global objects and not others, so this would follow a typical idiom.
Further, Apple has raised concerns about
cleanupSome being exposed on the Web at all, due to concerns about whether we want to encourage the "long job" programming style in a context where objects are also being used.
Discussion about where and whether
cleanupSome should be exposed in web browsers is ongoing in a WHATWG HTML issue.
cleanupSome into a separate proposal would give everyone time to consider its presence in browsers at its own pace.
Design changes over time
Earlier drafts of
cleanupSome had certain differences from the latest version:
cleanupSomereturned a boolean to indicate whether anything is cleaned up. Now,
cleanupSomecalls the callback with one value at a time, repeatedly.
These changes were made without the involvement of the people who made the previous design decisions. Splitting out
cleanupSome into a separate proposal would give the committee time to reconsider these design decisions.
Ecosystem impact of a proposal split vs normative optional
FinalizationRegistry.prototype.cleanupSome has been a bit confusing from an ecosystem perspective. For example,
- The TypeScript typing includes
cleanupSomebut marked as optional
- The MDN documentation notes that the method is "optional", but it's not really clear how this should be interpreted by readers.
WeakRef are standard, and this part is still under discussion.
FinalizationRegistry.prototype.cleanupSome has been off from the WeakRefs proposal and is at Stage 2.
This API was originally proposed in a form which would be WebAssembly-specific. See the historical document - Support for long wasm jobs for more details.