Skip to content

ECMAScript Explicit Resource Management proposal integration with web APIs #8557

@rbuckton

Description

@rbuckton

The ECMAScript Explicit Resource Management proposal is currently at Stage 2 and is nearing advancement Stage 3. I'd like to get a feel from WHATWG as to whether, and how, WHATWG might integrate the capabilities of this proposal into existing APIs. I've created a rough list of potential integration points in the proposal explainer.

What follows is a brief summary of the proposal. You can read more about the proposal in the proposal repository and the proposal specification text. If you are unfamiliar with the TC39 staging process, please see the TC39 process document.


The Explicit Resource Management proposal provides the ability for JavaScript users to leverage RAII ("Resource Acquisition is Initialization")-style declarations via the new using declaration:

{
  using x = acquireSomeResource();
  ...
} // 'x' is disposed when exiting Block

A using declaration is constant, block-scoped declaration (like const), and tracks its binding for disposal at the end of the containing block, regardless as to whether from a normal or abrupt completion. This allows for explicit control over the lifetime of a resource. A resource is an object with a Symbol.dispose method that, when called, should perform synchronous cleanup activities.

This kind of declaration is extremely useful when managing the scoping and lifetime of multiple resources, as it guarantees ordered cleanup of resources (excluding process/thread termination):

{
  using x = createResource1();
  using y = createResource2();
  ...
} // disposes 'y', then disposes 'x'

In addition, this proposal introduces a new DisposableStack constructor which allows a user to collect multiple disposable resources in a single disposable container, which is extremely helpful when composing disposable classes consisting of other resources:

class MyResource {
  #x;
  #y;
  #disposables;

  constructor() {
    using stack = new DisposableStack(); // 'stack' will be disposed at end of constructor
    this.#x = stack.use(createResource1()); // Add resource for '#x' to 'stack'
    this.#y = stack.use(createResource2()); // Add resource for '#y' to 'stack'

    // if either 'createResource1()' or 'createResource2()' throws, 'stack' and its contents
    // will be disposed.

    this.#disposables = stack.move(); // move resources out of 'stack' and into '#disposables'
    
    // disposes 'stack' (now empty), but not '#x', '#y', or '#disposables'
  }
  
  ...
  
  [Symbol.dispose]() {
    this.#disposables.dispose(); // disposes '#y' and '#x'
  }
}

Not all resources can be disposed of in a synchronous manner, however. This proposal also introduces Symbol.asyncDispose and an AsyncDisposableStack API for asynchronously disposed resources. These two APIs are part of the main proposal and are intended to advance to Stage 3. However, syntax for an asynchronous using declaration has been postponed to a follow-on proposal due to its possible dependency on async do expressions, though it will likely look something like the following:

async function f() {
  // body-scoped 'async using'
  async using x = someAsyncDisposableResource1();
  
  // block-scoped 'async using' requires an explicit 'await' marker:
  await async do {
    async using y = someAsyncDisposableResource2();
    ...
  }; // performs (roughly) 'await y?.[Symbol.asyncDispose]()
  
} // performs (roughly) 'await x?.[Symbol.asyncDispose]()

In summary, the following features are at Stage 2 and will be proposed for advancement to Stage 3 at the upcoming TC39 plenary:

  • using declarations — block-scoped, constant, synchronous disposal.
  • Symbol.dispose — built-in symbol, indicates disposal method.
  • Symbol.asyncDispose — built-in symbol, indicates async disposal method.
  • DisposableStack — disposable container.
  • AsyncDisposableStack — async disposable container.

The following features are at Stage 2 and have been postponed temporarily due to dependency on other proposals:

  • async using declarations — block-scoped, constant, asynchronous disposal.

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