Symbol.dispose

Marks the cleanup method that a using declaration calls when a variable leaves scope.

Signature
Symbol.dispose
// as implemented on an object:
[Symbol.dispose]()

Return value

symbolThe well-known symbol used as the property key for an object's synchronous cleanup method. The method's return value is ignored.

Errors

Throwing from [Symbol.dispose]() signals the resource could not be freed; using propagates that error, wrapping any error already in flight in a SuppressedError.

Changelog

  • PHP Explicit Resource ManagementIntroduced with the using declaration, DisposableStack and SuppressedError. MDN lists it as limited availability — it does not yet work in some widely used browsers.

Symbol.dispose is the key for an object's synchronous cleanup method. A using declaration reads it off the initializer and calls it automatically when the enclosing block exits — by normal completion, return, break or a thrown error:

{
  using file = openFile("a.txt");
  read(file);
} // file[Symbol.dispose]() runs here

When to reach for it

Implement it on anything that holds something needing release: a file or socket handle, a lock, a subscription, a temporary DOM listener, a database transaction. It replaces the hand-written try/finally pyramid, and disposal happens in reverse declaration order so resources unwind like a stack.

What trips people up

Support is still limited — MDN does not list it as Baseline, so check your engines or transpile. The method must be synchronous: using does not await a returned promise, so asynchronous teardown needs Symbol.asyncDispose and await using. Make it idempotent, since a second call should not throw. And using is block-scoped only: it is not allowed at the top level of a script, in a for...in head, or as a bare class field.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Release a file handle, socket or lock the moment its block ends
  • Unsubscribe from an event source without a try/finally wrapper
  • Roll back a database transaction automatically on an early return or throw

Frequently asked questions

What is the difference between Symbol.dispose and Symbol.asyncDispose?

Symbol.dispose is called synchronously by a using declaration and its return value is ignored, while Symbol.asyncDispose is called by await using and its returned promise is awaited. Use the async version whenever cleanup itself needs to await something.

Can I use `using` at the top level of a module?

Only inside a block. A using declaration must appear in a block, function body or module body scope where disposal has a clear end point; it is rejected in a script's top level and in for...in or for...of heads.

Does Symbol.dispose work in all browsers?

No. MDN lists it as limited availability rather than Baseline, so check the compatibility table for your targets or transpile the using syntax; the polyfill line Symbol.dispose ??= Symbol('Symbol.dispose') keeps library code interoperable.

More examples

What a using declaration does for you

The output shows the body running first, then "dispose b" before "dispose a" — using unwinds resources in reverse declaration order, exactly as this manual try/finally does.

Example · javascript
Symbol.dispose ??= Symbol("Symbol.dispose");

const make = (name) => ({
  name,
  [Symbol.dispose]() {
    console.log("dispose", name);
  },
});

// Equivalent to: { using a = make("a"); using b = make("b"); ... }
const a = make("a");
const b = make("b");
try {
  console.log("body", a.name, b.name);
} finally {
  b[Symbol.dispose]();
  a[Symbol.dispose]();
}

Detecting disposable objects

The shape check is the same one a using declaration performs. The final lines confirm the well-known symbol carries a description but, like all well-known symbols, has no global registry key.

Example · javascript
Symbol.dispose ??= Symbol("Symbol.dispose");

const isDisposable = (v) =>
  v != null && typeof v[Symbol.dispose] === "function";

console.log(isDisposable({ [Symbol.dispose]() {} }));
console.log(isDisposable({}));
console.log(isDisposable(null));
console.log(Symbol.dispose.description);
console.log(Symbol.keyFor(Symbol.dispose));

Discussion

  • Be the first to comment on this lesson.