await using does not simply call whichever cleanup property looks convenient. It asks for asynchronous disposal first. Only when Symbol.asyncDispose is absent does it read Symbol.dispose and create an internal Promise-returning wrapper. That wrapper converts a synchronous throw into rejection but deliberately does not await a Promise returned by the synchronous hook.
This specialist guide belongs to the Websites root. It also connects to The Gold Standard of Education | Learning That Transfers into Life and the How X Works hub. The worked cases are original teaching examples; their numbers are stipulated so that the reasoning can be checked.
eduKateSG · Websites
Find your next learning step
Trace await using async-first disposal lookup, synchronous Symbol.dispose fallback, Promise wrapping, throw-to-rejection conversion and deliberate non-adoption of a sync return value.
ROUTE 1 · CHAPTERS 1–3
Build the resource model
Identify the registered value, cleanup method, stack state and initiating operation.
ROUTE 2 · CHAPTERS 4–6
Trace normal cleanup
Follow registration, reverse order, receiver binding and returned values in sequence.
ROUTE 3 · CHAPTERS 7–9
Change one condition
Rebuild the trace when ownership, method availability, scope completion or timing changes.
ROUTE 4 · CHAPTERS 10–12
Handle failures and limits
Track abrupt completion, error precedence, repeated requests and bounded claims.
ROUTE 5 · CHAPTERS 13–15
Test and explain
Design decisive fixtures, review code and transfer the reasoning to another resource.
Chapter contents
Build the resource model · Chapters 1–3
1. Distinguish using from await using
Trace normal cleanup · Chapters 4–6
4. Reject a resource with neither method
Change one condition · Chapters 7–9
7. Preserve the resource as this
Handle failures and limits · Chapters 10–12
10. Await the real async method result
Test and explain · Chapters 13–15
13. Compare for await with await using
14. Design a dual-symbol fixture
15. Explain fallback without calling it awaitable sync cleanup
using requests sync-dispose lookup, while await using requests async-dispose lookup with a defined synchronous fallback. Name the resource value, the cleanup function actually stored, the stack state before the step and the operation that initiates cleanup. That ledger prevents a familiar final log from concealing earlier validation or ownership transfer.
Worked case. Give one object only Symbol.dispose and show using works directly while await using accepts it through the fallback wrapper. Write the event ledger before predicting the result: registration, method lookup, callback creation, state change, cleanup call, thrown value and caller observation all get separate entries.
Follow the specified order. Identify the first step that selects this branch, then mark which records remain on the stack and which completion is carried forward. The final exception or return value makes sense only after those intermediate facts are visible.
Changed-context check. Give another object only Symbol.asyncDispose and show await using works while plain using rejects. Rebuild the ledger from the changed premise. Compare registration effects, reverse-order calls, receivers, promise settlement and the state of both old and new stacks wherever the mechanism makes them observable.
Limit and misconception check. The await marker selects disposal semantics; it does not describe how the resource was acquired. Keep the claim tied to the fixture. A logging object cannot by itself prove behaviour for proxies, host resources, re-entrant cleanup, implementation bugs or APIs whose release methods have undocumented side effects.
For a practical evidence check, instrument every cleanup method or adapter, record this and arguments, expose the disposed getter where relevant and assert the complete ordered log. A test that checks only the last error can pass even when ownership or cleanup order is wrong.
A useful review separates three layers. The resource decides what its cleanup function does; the stack or declaration decides when and in what order to call it; the surrounding code observes normal completion, a thrown value or Promise settlement. Mixing those layers creates false causal stories.
Transfer the chapter into a compact explanation: state the starting state, the decisive algorithm step, the observed result and one caveat. Then change one condition and predict the first point where the new trace diverges. This turns one example into a reusable resource-lifecycle model.
GetDisposeMethod for async-dispose reads Symbol.asyncDispose before considering Symbol.dispose. Name the resource value, the cleanup function actually stored, the stack state before the step and the operation that initiates cleanup. That ledger prevents a familiar final log from concealing earlier validation or ownership transfer.
Worked case. An object defines getters for both symbols; await using logs only the async getter and uses its method. Write the event ledger before predicting the result: registration, method lookup, callback creation, state change, cleanup call, thrown value and caller observation all get separate entries.
Follow the specified order. Identify the first step that selects this branch, then mark which records remain on the stack and which completion is carried forward. The final exception or return value makes sense only after those intermediate facts are visible.
Changed-context check. Return undefined from the async getter and observe the later sync lookup. Rebuild the ledger from the changed premise. Compare registration effects, reverse-order calls, receivers, promise settlement and the state of both old and new stacks wherever the mechanism makes them observable.
Limit and misconception check. A present callable async method prevents fallback even if a sync method also exists. Keep the claim tied to the fixture. A logging object cannot by itself prove behaviour for proxies, host resources, re-entrant cleanup, implementation bugs or APIs whose release methods have undocumented side effects.
For a practical evidence check, instrument every cleanup method or adapter, record this and arguments, expose the disposed getter where relevant and assert the complete ordered log. A test that checks only the last error can pass even when ownership or cleanup order is wrong.
A useful review separates three layers. The resource decides what its cleanup function does; the stack or declaration decides when and in what order to call it; the surrounding code observes normal completion, a thrown value or Promise settlement. Mixing those layers creates false causal stories.
Transfer the chapter into a compact explanation: state the starting state, the decisive algorithm step, the observed result and one caveat. Then change one condition and predict the first point where the new trace diverges. This turns one example into a reusable resource-lifecycle model.
CHAPTER 3 OF 15 · Build the resource model
3. Fall back only when the async method is absent
Undefined async cleanup triggers a Symbol.dispose lookup; a non-callable async property throws instead of falling back. Name the resource value, the cleanup function actually stored, the stack state before the step and the operation that initiates cleanup. That ledger prevents a familiar final log from concealing earlier validation or ownership transfer.
Worked case. Set Symbol.asyncDispose to 7 and Symbol.dispose to a function; registration throws TypeError at the async lookup. Write the event ledger before predicting the result: registration, method lookup, callback creation, state change, cleanup call, thrown value and caller observation all get separate entries.
Follow the specified order. Identify the first step that selects this branch, then mark which records remain on the stack and which completion is carried forward. The final exception or return value makes sense only after those intermediate facts are visible.
Changed-context check. Set the async property to undefined and the sync method becomes eligible. Rebuild the ledger from the changed premise. Compare registration effects, reverse-order calls, receivers, promise settlement and the state of both old and new stacks wherever the mechanism makes them observable.
Limit and misconception check. Fallback is not error recovery for a malformed async method. Keep the claim tied to the fixture. A logging object cannot by itself prove behaviour for proxies, host resources, re-entrant cleanup, implementation bugs or APIs whose release methods have undocumented side effects.
For a practical evidence check, instrument every cleanup method or adapter, record this and arguments, expose the disposed getter where relevant and assert the complete ordered log. A test that checks only the last error can pass even when ownership or cleanup order is wrong.
A useful review separates three layers. The resource decides what its cleanup function does; the stack or declaration decides when and in what order to call it; the surrounding code observes normal completion, a thrown value or Promise settlement. Mixing those layers creates false causal stories.
Transfer the chapter into a compact explanation: state the starting state, the decisive algorithm step, the observed result and one caveat. Then change one condition and predict the first point where the new trace diverges. This turns one example into a reusable resource-lifecycle model.
After both lookups yield undefined for a non-null object, disposable-resource creation throws TypeError. Name the resource value, the cleanup function actually stored, the stack state before the step and the operation that initiates cleanup. That ledger prevents a familiar final log from concealing earlier validation or ownership transfer.
Worked case. await using binds {}; registration fails before the body using the binding runs. Write the event ledger before predicting the result: registration, method lookup, callback creation, state change, cleanup call, thrown value and caller observation all get separate entries.
Follow the specified order. Identify the first step that selects this branch, then mark which records remain on the stack and which completion is carried forward. The final exception or return value makes sense only after those intermediate facts are visible.
Changed-context check. Add a sync dispose method and repeat through the fallback path. Rebuild the ledger from the changed premise. Compare registration effects, reverse-order calls, receivers, promise settlement and the state of both old and new stacks wherever the mechanism makes them observable.
Limit and misconception check. An ordinary object is not accepted merely because cleanup might be unnecessary. Keep the claim tied to the fixture. A logging object cannot by itself prove behaviour for proxies, host resources, re-entrant cleanup, implementation bugs or APIs whose release methods have undocumented side effects.
For a practical evidence check, instrument every cleanup method or adapter, record this and arguments, expose the disposed getter where relevant and assert the complete ordered log. A test that checks only the last error can pass even when ownership or cleanup order is wrong.
A useful review separates three layers. The resource decides what its cleanup function does; the stack or declaration decides when and in what order to call it; the surrounding code observes normal completion, a thrown value or Promise settlement. Mixing those layers creates false causal stories.
Transfer the chapter into a compact explanation: state the starting state, the decisive algorithm step, the observed result and one caveat. Then change one condition and predict the first point where the new trace diverges. This turns one example into a reusable resource-lifecycle model.
Nullish await-using values create a record with no method so that scope control remains well-defined. Name the resource value, the cleanup function actually stored, the stack state before the step and the operation that initiates cleanup. That ledger prevents a familiar final log from concealing earlier validation or ownership transfer.
Worked case. Bind await using x=null, log before exit and after the asynchronous boundary. Write the event ledger before predicting the result: registration, method lookup, callback creation, state change, cleanup call, thrown value and caller observation all get separate entries.
Follow the specified order. Identify the first step that selects this branch, then mark which records remain on the stack and which completion is carried forward. The final exception or return value makes sense only after those intermediate facts are visible.
Changed-context check. Replace null with 0 and registration throws TypeError. Rebuild the ledger from the changed premise. Compare registration effects, reverse-order calls, receivers, promise settlement and the state of both old and new stacks wherever the mechanism makes them observable.
Limit and misconception check. Nullish tolerance is narrow and does not extend to all primitives. Keep the claim tied to the fixture. A logging object cannot by itself prove behaviour for proxies, host resources, re-entrant cleanup, implementation bugs or APIs whose release methods have undocumented side effects.
For a practical evidence check, instrument every cleanup method or adapter, record this and arguments, expose the disposed getter where relevant and assert the complete ordered log. A test that checks only the last error can pass even when ownership or cleanup order is wrong.
A useful review separates three layers. The resource decides what its cleanup function does; the stack or declaration decides when and in what order to call it; the surrounding code observes normal completion, a thrown value or Promise settlement. Mixing those layers creates false causal stories.
Transfer the chapter into a compact explanation: state the starting state, the decisive algorithm step, the observed result and one caveat. Then change one condition and predict the first point where the new trace diverges. This turns one example into a reusable resource-lifecycle model.
CHAPTER 6 OF 15 · Trace normal cleanup
6. Wrap synchronous cleanup in a Promise protocol
The fallback creates an internal function that calls the sync method and returns a Promise fulfilled with undefined or rejected on a throw. Name the resource value, the cleanup function actually stored, the stack state before the step and the operation that initiates cleanup. That ledger prevents a familiar final log from concealing earlier validation or ownership transfer.
Worked case. A sync method logs and returns a custom Promise object; the wrapper resolves undefined rather than adopting that returned Promise. Write the event ledger before predicting the result: registration, method lookup, callback creation, state change, cleanup call, thrown value and caller observation all get separate entries.
Follow the specified order. Identify the first step that selects this branch, then mark which records remain on the stack and which completion is carried forward. The final exception or return value makes sense only after those intermediate facts are visible.
Changed-context check. Make the sync method throw and observe a rejected wrapper Promise. Rebuild the ledger from the changed premise. Compare registration effects, reverse-order calls, receivers, promise settlement and the state of both old and new stacks wherever the mechanism makes them observable.
Limit and misconception check. This fallback deliberately does not await a Promise returned by Symbol.dispose. Keep the claim tied to the fixture. A logging object cannot by itself prove behaviour for proxies, host resources, re-entrant cleanup, implementation bugs or APIs whose release methods have undocumented side effects.
For a practical evidence check, instrument every cleanup method or adapter, record this and arguments, expose the disposed getter where relevant and assert the complete ordered log. A test that checks only the last error can pass even when ownership or cleanup order is wrong.
A useful review separates three layers. The resource decides what its cleanup function does; the stack or declaration decides when and in what order to call it; the surrounding code observes normal completion, a thrown value or Promise settlement. Mixing those layers creates false causal stories.
Transfer the chapter into a compact explanation: state the starting state, the decisive algorithm step, the observed result and one caveat. Then change one condition and predict the first point where the new trace diverges. This turns one example into a reusable resource-lifecycle model.
The fallback function calls the captured sync method with the original resource object as its receiver. Name the resource value, the cleanup function actually stored, the stack state before the step and the operation that initiates cleanup. That ledger prevents a familiar final log from concealing earlier validation or ownership transfer.
Worked case. A sync disposer checks this===resource under await using and passes. Write the event ledger before predicting the result: registration, method lookup, callback creation, state change, cleanup call, thrown value and caller observation all get separate entries.
Follow the specified order. Identify the first step that selects this branch, then mark which records remain on the stack and which completion is carried forward. The final exception or return value makes sense only after those intermediate facts are visible.
Changed-context check. Detach the same method and call it plainly to expose receiver dependence. Rebuild the ledger from the changed premise. Compare registration effects, reverse-order calls, receivers, promise settlement and the state of both old and new stacks wherever the mechanism makes them observable.
Limit and misconception check. The internal wrapper is not a new public owner of the resource. Keep the claim tied to the fixture. A logging object cannot by itself prove behaviour for proxies, host resources, re-entrant cleanup, implementation bugs or APIs whose release methods have undocumented side effects.
For a practical evidence check, instrument every cleanup method or adapter, record this and arguments, expose the disposed getter where relevant and assert the complete ordered log. A test that checks only the last error can pass even when ownership or cleanup order is wrong.
A useful review separates three layers. The resource decides what its cleanup function does; the stack or declaration decides when and in what order to call it; the surrounding code observes normal completion, a thrown value or Promise settlement. Mixing those layers creates false causal stories.
Transfer the chapter into a compact explanation: state the starting state, the decisive algorithm step, the observed result and one caveat. Then change one condition and predict the first point where the new trace diverges. This turns one example into a reusable resource-lifecycle model.
CHAPTER 8 OF 15 · Change one condition
8. Translate synchronous throws into rejection
If the fallback sync method throws, IfAbruptRejectPromise rejects the created capability rather than throwing from the wrapper call. Name the resource value, the cleanup function actually stored, the stack state before the step and the operation that initiates cleanup. That ledger prevents a familiar final log from concealing earlier validation or ownership transfer.
Worked case. Scope exit calls a sync disposer that throws syncError; the surrounding async control observes rejection. Write the event ledger before predicting the result: registration, method lookup, callback creation, state change, cleanup call, thrown value and caller observation all get separate entries.
Follow the specified order. Identify the first step that selects this branch, then mark which records remain on the stack and which completion is carried forward. The final exception or return value makes sense only after those intermediate facts are visible.
Changed-context check. Make the disposer return normally and continuation occurs after fulfilment. Rebuild the ledger from the changed premise. Compare registration effects, reverse-order calls, receivers, promise settlement and the state of both old and new stacks wherever the mechanism makes them observable.
Limit and misconception check. Registration-time getter errors still happen during method discovery and follow the surrounding evaluation rules. Keep the claim tied to the fixture. A logging object cannot by itself prove behaviour for proxies, host resources, re-entrant cleanup, implementation bugs or APIs whose release methods have undocumented side effects.
For a practical evidence check, instrument every cleanup method or adapter, record this and arguments, expose the disposed getter where relevant and assert the complete ordered log. A test that checks only the last error can pass even when ownership or cleanup order is wrong.
A useful review separates three layers. The resource decides what its cleanup function does; the stack or declaration decides when and in what order to call it; the surrounding code observes normal completion, a thrown value or Promise settlement. Mixing those layers creates false causal stories.
Transfer the chapter into a compact explanation: state the starting state, the decisive algorithm step, the observed result and one caveat. Then change one condition and predict the first point where the new trace diverges. This turns one example into a reusable resource-lifecycle model.
CHAPTER 9 OF 15 · Change one condition
9. Ignore a Promise returned by Symbol.dispose fallback
The fallback resolves its own Promise with undefined after a normal sync call, without adopting that call returned value. Name the resource value, the cleanup function actually stored, the stack state before the step and the operation that initiates cleanup. That ledger prevents a familiar final log from concealing earlier validation or ownership transfer.
Worked case. Symbol.dispose returns a later-rejecting Promise; await using fallback proceeds from its own fulfilled Promise and the stray rejection must be handled separately. Write the event ledger before predicting the result: registration, method lookup, callback creation, state change, cleanup call, thrown value and caller observation all get separate entries.
Follow the specified order. Identify the first step that selects this branch, then mark which records remain on the stack and which completion is carried forward. The final exception or return value makes sense only after those intermediate facts are visible.
Changed-context check. Move the method to Symbol.asyncDispose and its returned Promise is awaited. Rebuild the ledger from the changed premise. Compare registration effects, reverse-order calls, receivers, promise settlement and the state of both old and new stacks wherever the mechanism makes them observable.
Limit and misconception check. Returning a Promise from a synchronous disposal hook does not convert it into asynchronous disposal. Keep the claim tied to the fixture. A logging object cannot by itself prove behaviour for proxies, host resources, re-entrant cleanup, implementation bugs or APIs whose release methods have undocumented side effects.
For a practical evidence check, instrument every cleanup method or adapter, record this and arguments, expose the disposed getter where relevant and assert the complete ordered log. A test that checks only the last error can pass even when ownership or cleanup order is wrong.
A useful review separates three layers. The resource decides what its cleanup function does; the stack or declaration decides when and in what order to call it; the surrounding code observes normal completion, a thrown value or Promise settlement. Mixing those layers creates false causal stories.
Transfer the chapter into a compact explanation: state the starting state, the decisive algorithm step, the observed result and one caveat. Then change one condition and predict the first point where the new trace diverges. This turns one example into a reusable resource-lifecycle model.
CHAPTER 10 OF 15 · Handle failures and limits
10. Await the real async method result
When Symbol.asyncDispose is selected, DisposeResources awaits its returned value before leaving the resource scope. Name the resource value, the cleanup function actually stored, the stack state before the step and the operation that initiates cleanup. That ledger prevents a familiar final log from concealing earlier validation or ownership transfer.
Worked case. Async cleanup returns a controllable Promise; code after the scope waits until it fulfils. Write the event ledger before predicting the result: registration, method lookup, callback creation, state change, cleanup call, thrown value and caller observation all get separate entries.
Follow the specified order. Identify the first step that selects this branch, then mark which records remain on the stack and which completion is carried forward. The final exception or return value makes sense only after those intermediate facts are visible.
Changed-context check. Reject the same Promise and observe cleanup failure instead of continuation. Rebuild the ledger from the changed premise. Compare registration effects, reverse-order calls, receivers, promise settlement and the state of both old and new stacks wherever the mechanism makes them observable.
Limit and misconception check. Await coordinates Promise settlement; it does not block the JavaScript thread. Keep the claim tied to the fixture. A logging object cannot by itself prove behaviour for proxies, host resources, re-entrant cleanup, implementation bugs or APIs whose release methods have undocumented side effects.
For a practical evidence check, instrument every cleanup method or adapter, record this and arguments, expose the disposed getter where relevant and assert the complete ordered log. A test that checks only the last error can pass even when ownership or cleanup order is wrong.
A useful review separates three layers. The resource decides what its cleanup function does; the stack or declaration decides when and in what order to call it; the surrounding code observes normal completion, a thrown value or Promise settlement. Mixing those layers creates false causal stories.
Transfer the chapter into a compact explanation: state the starting state, the decisive algorithm step, the observed result and one caveat. Then change one condition and predict the first point where the new trace diverges. This turns one example into a reusable resource-lifecycle model.
Symbol getters and proxies can reveal async-first then sync-fallback lookup order during registration. Name the resource value, the cleanup function actually stored, the stack state before the step and the operation that initiates cleanup. That ledger prevents a familiar final log from concealing earlier validation or ownership transfer.
Worked case. A proxy logs get asyncDispose followed by get dispose when the first returns undefined. Write the event ledger before predicting the result: registration, method lookup, callback creation, state change, cleanup call, thrown value and caller observation all get separate entries.
Follow the specified order. Identify the first step that selects this branch, then mark which records remain on the stack and which completion is carried forward. The final exception or return value makes sense only after those intermediate facts are visible.
Changed-context check. Make asyncDispose callable and the second get disappears. Rebuild the ledger from the changed premise. Compare registration effects, reverse-order calls, receivers, promise settlement and the state of both old and new stacks wherever the mechanism makes them observable.
Limit and misconception check. Ordinary data properties hide lookup timing, so a plain object fixture cannot prove the order. Keep the claim tied to the fixture. A logging object cannot by itself prove behaviour for proxies, host resources, re-entrant cleanup, implementation bugs or APIs whose release methods have undocumented side effects.
For a practical evidence check, instrument every cleanup method or adapter, record this and arguments, expose the disposed getter where relevant and assert the complete ordered log. A test that checks only the last error can pass even when ownership or cleanup order is wrong.
A useful review separates three layers. The resource decides what its cleanup function does; the stack or declaration decides when and in what order to call it; the surrounding code observes normal completion, a thrown value or Promise settlement. Mixing those layers creates false causal stories.
Transfer the chapter into a compact explanation: state the starting state, the decisive algorithm step, the observed result and one caveat. Then change one condition and predict the first point where the new trace diverges. This turns one example into a reusable resource-lifecycle model.
CHAPTER 12 OF 15 · Handle failures and limits
12. Separate acquisition await from disposal await
The initializer may itself use await, and await using later introduces a distinct await during scope exit. Name the resource value, the cleanup function actually stored, the stack state before the step and the operation that initiates cleanup. That ledger prevents a familiar final log from concealing earlier validation or ownership transfer.
Worked case. Await a resource factory, enter the body, then await async disposal; log both suspension boundaries. Write the event ledger before predicting the result: registration, method lookup, callback creation, state change, cleanup call, thrown value and caller observation all get separate entries.
Follow the specified order. Identify the first step that selects this branch, then mark which records remain on the stack and which completion is carried forward. The final exception or return value makes sense only after those intermediate facts are visible.
Changed-context check. Use an already available resource and retain only the cleanup await. Rebuild the ledger from the changed premise. Compare registration effects, reverse-order calls, receivers, promise settlement and the state of both old and new stacks wherever the mechanism makes them observable.
Limit and misconception check. Two awaits in one declaration region serve different causal roles. Keep the claim tied to the fixture. A logging object cannot by itself prove behaviour for proxies, host resources, re-entrant cleanup, implementation bugs or APIs whose release methods have undocumented side effects.
For a practical evidence check, instrument every cleanup method or adapter, record this and arguments, expose the disposed getter where relevant and assert the complete ordered log. A test that checks only the last error can pass even when ownership or cleanup order is wrong.
A useful review separates three layers. The resource decides what its cleanup function does; the stack or declaration decides when and in what order to call it; the surrounding code observes normal completion, a thrown value or Promise settlement. Mixing those layers creates false causal stories.
Transfer the chapter into a compact explanation: state the starting state, the decisive algorithm step, the observed result and one caveat. Then change one condition and predict the first point where the new trace diverges. This turns one example into a reusable resource-lifecycle model.
for await controls how iteration obtains values, while await using controls how each bound value is disposed. Name the resource value, the cleanup function actually stored, the stack state before the step and the operation that initiates cleanup. That ledger prevents a familiar final log from concealing earlier validation or ownership transfer.
Worked case. Run for await (await using x of source) and log iteration next separately from per-iteration async cleanup. Write the event ledger before predicting the result: registration, method lookup, callback creation, state change, cleanup call, thrown value and caller observation all get separate entries.
Follow the specified order. Identify the first step that selects this branch, then mark which records remain on the stack and which completion is carried forward. The final exception or return value makes sense only after those intermediate facts are visible.
Changed-context check. Change to for await (using x of source) and require each value to support synchronous disposal. Rebuild the ledger from the changed premise. Compare registration effects, reverse-order calls, receivers, promise settlement and the state of both old and new stacks wherever the mechanism makes them observable.
Limit and misconception check. The two await markers are independent and neither implies the other. Keep the claim tied to the fixture. A logging object cannot by itself prove behaviour for proxies, host resources, re-entrant cleanup, implementation bugs or APIs whose release methods have undocumented side effects.
For a practical evidence check, instrument every cleanup method or adapter, record this and arguments, expose the disposed getter where relevant and assert the complete ordered log. A test that checks only the last error can pass even when ownership or cleanup order is wrong.
A useful review separates three layers. The resource decides what its cleanup function does; the stack or declaration decides when and in what order to call it; the surrounding code observes normal completion, a thrown value or Promise settlement. Mixing those layers creates false causal stories.
Transfer the chapter into a compact explanation: state the starting state, the decisive algorithm step, the observed result and one caveat. Then change one condition and predict the first point where the new trace diverges. This turns one example into a reusable resource-lifecycle model.
A decisive fixture gives one resource logged getters and methods for both symbols plus controllable return values. Name the resource value, the cleanup function actually stored, the stack state before the step and the operation that initiates cleanup. That ledger prevents a familiar final log from concealing earlier validation or ownership transfer.
Worked case. Assert async-first lookup, no sync lookup when async exists, receiver identity and delayed continuation. Write the event ledger before predicting the result: registration, method lookup, callback creation, state change, cleanup call, thrown value and caller observation all get separate entries.
Follow the specified order. Identify the first step that selects this branch, then mark which records remain on the stack and which completion is carried forward. The final exception or return value makes sense only after those intermediate facts are visible.
Changed-context check. Set async to undefined and make sync return a rejecting Promise to demonstrate non-adoption. Rebuild the ledger from the changed premise. Compare registration effects, reverse-order calls, receivers, promise settlement and the state of both old and new stacks wherever the mechanism makes them observable.
Limit and misconception check. One resource with only one method cannot expose fallback selection. Keep the claim tied to the fixture. A logging object cannot by itself prove behaviour for proxies, host resources, re-entrant cleanup, implementation bugs or APIs whose release methods have undocumented side effects.
For a practical evidence check, instrument every cleanup method or adapter, record this and arguments, expose the disposed getter where relevant and assert the complete ordered log. A test that checks only the last error can pass even when ownership or cleanup order is wrong.
A useful review separates three layers. The resource decides what its cleanup function does; the stack or declaration decides when and in what order to call it; the surrounding code observes normal completion, a thrown value or Promise settlement. Mixing those layers creates false causal stories.
Transfer the chapter into a compact explanation: state the starting state, the decisive algorithm step, the observed result and one caveat. Then change one condition and predict the first point where the new trace diverges. This turns one example into a reusable resource-lifecycle model.
CHAPTER 15 OF 15 · Test and explain
15. Explain fallback without calling it awaitable sync cleanup
A complete explanation states async lookup, conditional sync lookup, internal Promise wrapper and the deliberate non-adoption of a sync return value. Name the resource value, the cleanup function actually stored, the stack state before the step and the operation that initiates cleanup. That ledger prevents a familiar final log from concealing earlier validation or ownership transfer.
Worked case. Report that await using selected Symbol.dispose only because asyncDispose was absent, converted a sync throw to rejection and fulfilled undefined on normal return. Write the event ledger before predicting the result: registration, method lookup, callback creation, state change, cleanup call, thrown value and caller observation all get separate entries.
Follow the specified order. Identify the first step that selects this branch, then mark which records remain on the stack and which completion is carried forward. The final exception or return value makes sense only after those intermediate facts are visible.
Changed-context check. Changed report: callable asyncDispose exists, so its result is actually awaited and syncDispose is not read. Rebuild the ledger from the changed premise. Compare registration effects, reverse-order calls, receivers, promise settlement and the state of both old and new stacks wherever the mechanism makes them observable.
Limit and misconception check. Do not say await using makes every synchronous disposer asynchronous; it supplies asynchronous control flow around a still-synchronous method. Keep the claim tied to the fixture. A logging object cannot by itself prove behaviour for proxies, host resources, re-entrant cleanup, implementation bugs or APIs whose release methods have undocumented side effects.
For a practical evidence check, instrument every cleanup method or adapter, record this and arguments, expose the disposed getter where relevant and assert the complete ordered log. A test that checks only the last error can pass even when ownership or cleanup order is wrong.
A useful review separates three layers. The resource decides what its cleanup function does; the stack or declaration decides when and in what order to call it; the surrounding code observes normal completion, a thrown value or Promise settlement. Mixing those layers creates false causal stories.
Transfer the chapter into a compact explanation: state the starting state, the decisive algorithm step, the observed result and one caveat. Then change one condition and predict the first point where the new trace diverges. This turns one example into a reusable resource-lifecycle model.
Continue with connected lessons
Trace async iterator disposal itself
Trace async iterator disposal itself. Compare a real Symbol.asyncDispose method with declaration-level fallback selection.
Trace synchronous iterator disposal
Trace synchronous iterator disposal. Review the synchronous hook that await using may wrap.
Compare Promise cleanup outcomes
Compare Promise cleanup outcomes. Connect rejection timing with another Promise cleanup mechanism.
Frequently asked questions
Which method does await using prefer?
Symbol.asyncDispose.
When does it fall back?
Only when the async method is absent, then it looks for Symbol.dispose.
What if asyncDispose is present but non-callable?
Registration throws TypeError; it does not fall back.
Is a Promise returned by Symbol.dispose awaited?
No. The fallback wrapper ignores that normal return value.
What if the sync disposer throws?
The fallback Promise rejects with that error.
Can await using bind null?
Yes. Null and undefined are permitted empty resource values.
Authoritative sources and further reading
ECMAScript: GetDisposeMethod. Normative async-first lookup and synchronous fallback wrapper.
ECMAScript: DisposeResources. Awaiting async cleanup records and carrying completion.
TC39 explicit resource management proposal. Syntax and behavioural matrix for using and await using.
Return to the Websites subject guide, The Gold Standard of Education, or the How X Works hub.