The AsyncDisposableStack.use() is equivalent to await using. But there's no API equivalent to using on AsyncDisposableStack. This can lead to subtle behavior difference if there's async race:
import { describe, expect, test, jest } from "@jest/globals";
require("disposablestack/auto");
function listen(target: EventTarget, event: string, callback: (e: Event) => void): Disposable {
target.addEventListener(event, callback);
return { [Symbol.dispose]() { target.removeEventListener(event, callback); } };
}
function race(target: EventTarget, event: Event, resolve: () => void): Disposable {
return { [Symbol.dispose]() {
Promise.resolve().then(() => {
target.dispatchEvent(event);
resolve();
});
} };
}
class MyEvent extends Event {
constructor(name: string, public n: number) {
super(name);
}
}
describe("Async race in dispose", () => {
test("using", async () => {
const log = jest.fn();
await expect(new Promise<void>((resolve) => {
const target = new EventTarget();
using listener = listen(target, "event", ({ n }: any) => { log(n) });
using _ = race(target, new MyEvent("event", 2), resolve);
target.dispatchEvent(new MyEvent("event", 1));
})).resolves.not.toThrow();
expect(log.mock.calls).toStrictEqual([[1]]);
});
test("await using", async () => {
const log = jest.fn();
await expect(new Promise<void>(async (resolve) => {
const target = new EventTarget();
await using listener = listen(target, "event", ({ n }: any) => { log(n) });
await using _ = race(target, new MyEvent("event", 2), resolve);
target.dispatchEvent(new MyEvent("event", 1));
})).resolves.not.toThrow();
expect(log.mock.calls).toStrictEqual([[1], [2]]);
});
test("DisposableStack", async () => {
const log = jest.fn();
await expect(new Promise<void>((resolve) => {
using stack = new DisposableStack();
const target = new EventTarget();
stack.use(listen(target, "event", ({ n }: any) => { log(n) }));
stack.use(race(target, new MyEvent("event", 2), resolve));
target.dispatchEvent(new MyEvent("event", 1));
})).resolves.not.toThrow();
expect(log.mock.calls).toStrictEqual([[1]]);
});
test("AsyncDisposableStack", async () => {
const log = jest.fn();
await expect(new Promise<void>(async (resolve) => {
await using stack = new AsyncDisposableStack();
const target = new EventTarget();
stack.use(listen(target, "event", ({ n }: any) => { log(n) }));
stack.use(race(target, new MyEvent("event", 2), resolve));
target.dispatchEvent(new MyEvent("event", 1));
})).resolves.not.toThrow();
expect(log.mock.calls).toStrictEqual([[1], [2]]);
});
});
The
AsyncDisposableStack.use()is equivalent toawait using. But there's no API equivalent tousingonAsyncDisposableStack. This can lead to subtle behavior difference if there's async race: