Skip to content
This repository was archived by the owner on Jun 20, 2023. It is now read-only.

Allow AsyncDisposableStack to also add synchronous items #14

@Jamesernator

Description

@Jamesernator

So it's possible to have resources that define both [Symbol.dispose] and [Symbol.disposeAsync]:

const fileResource = {
    [Symbol.dispose]: () => { fs.closeSync(fd); },
    [Symbol.disposeAsync]: async () => { 
        return await new Promise((resolve) => {
            fs.close(fd, () => resolve());
        });
    }
}

Within a block we could use either using or await using to pick which disposal method to use:

{
    using fileResourceSync = makeFileResource();
    await using fileResourceAsync = makeFileResource();
}

However under the semantics of asyncDisposableStack.use, it will always use [Symbol.disposeAsync] regardless of which we might wish to use.

Furthermore (although less important IMO) is the fact that even if [Symbol.disposeAsync] is not on the resource, a microtask will occur between successive sync cleanups, which could be observed:

asyncDisposableStack.use({
    [Symbol.dispose]: () => {
        console.log("Cleanup res1");
        Promise.resolve().then(() => console.log("Before cleanup res2"));
    },
});
asyncDisposableStack.use({
    [Symbol.dispose]: () => {
        console.log("Cleanup res2");
    },
});

I'd like to propose that we have an additional .useSync method on AsyncDisposableStack so that we choose to use [Symbol.dispose] even if [Symbol.disposeAsync] for the resource were available.

(NOTE: I am not proposing that asyncDisposableStack.dispose() changes in any-way, this would still unconditionally return a promise).

This would be a fairly minimal addition, the spec text is pretty much the same as .use just with the other hint:

AsyncDisposableStack.prototype.use( value )
When the use function is called with one argument, the following steps are taken:

1. Let asyncDisposableStack be the this value.
2. Perform ? [RequireInternalSlot](https://tc39.es/ecma262/#sec-requireinternalslot)(asyncDisposableStack, [[AsyncDisposableState]]).
3. If asyncDisposableStack.[[AsyncDisposableState]] is disposed, throw a ReferenceError exception.
4. Perform ? [AddDisposableResource](https://tc39.es/proposal-async-explicit-resource-management/#sec-adddisposableresource-disposable-v-hint-disposemethod)(asyncDisposableStack.[[DisposeCapability]], value, sync-dispose).
5. Return value.

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