Movatterモバイル変換


[0]ホーム

URL:


  1. Web
  2. JavaScript
  3. Reference
  4. Statements and declarations
  5. await using

await using

Limited availability

This feature is not Baseline because it does not work in some of the most widely-used browsers.

Theawait using declaration declares block-scoped local variables that areasynchronously disposed. Likeconst, variables declared withawait using must be initialized and cannot be reassigned. The variable's value must be eithernull,undefined, or an object with a[Symbol.asyncDispose]() or[Symbol.dispose]() method. When the variable goes out of scope, the[Symbol.asyncDispose]() or[Symbol.dispose]() method of the object is called and awaited, to ensure that resources are freed.

Syntax

js
await using name1 = value1;await using name1 = value1, name2 = value2;await using name1 = value1, name2 = value2, /* …, */ nameN = valueN;
nameN

The name of the variable to declare. Each must be a legal JavaScriptidentifier andnot adestructuring binding pattern.

valueN

Initial value of the variable. It can be any legal expression but its value must be eithernull,undefined, or an object with a[Symbol.asyncDispose]() or[Symbol.dispose]() method.

Description

This declaration can only be used in places where bothawait andusing can be used, which include:

Anawait using declares an async disposable resource that's tied to the lifetime of the variable's scope (block, function, module, etc.). When the scope exits, the resource is disposed of asynchronously. Its syntax may be somewhat confusing, because theawait does not have an awaiting effect when the variable is first declared, but only when the variable goes out of scope.

When a variable is first declared and its value is non-nullish, adisposer is retrieved from the object. The[Symbol.asyncDispose] property is tried first, and falls back to[Symbol.dispose] if[Symbol.asyncDispose] isundefined. If neither property contains a function, aTypeError is thrown. Notably, the[Symbol.dispose]() method is wrapped into a function that looks likeasync () => { object[Symbol.dispose](); }, which means if it returns a promise, that promise isnot awaited. This disposer is saved to the scope.

When the variable goes out of scope, the disposer is called and awaited. If the scope contains multipleusing orawait using declarations, all disposers are run in sequence in the reverse order of declaration, regardless of the type of declaration. All disposers are guaranteed to run (much like thefinally block intry...catch...finally). All errors thrown during disposal, including the initial error that caused the scope exit (if applicable), are all aggregated inside oneSuppressedError, with each earlier exception as thesuppressed property and the later exception as theerror property. ThisSuppressedError is thrown after disposal is complete.

The variable is allowed to have valuenull orundefined, so the resource can be optionally present. As long as oneawait using variable is declared in this scope, at least oneawait is guaranteed to happen on scope exit, even if the variable actually has valuenull orundefined. This prevents the disposal from happening synchronously, causing timing issues (seecontrol flow effects ofawait).

await using ties resource management to lexical scopes, which is both convenient and sometimes confusing. See below for some examples where it may not behave how you expect. If you want to hand-manage resource disposal, while maintaining the same error handling guarantees, you can useAsyncDisposableStack instead.

Examples

You should also checkusing for more examples, especially some general caveats with respect to scope-based resource management.

Basic usage

Usually, you useawait using on some library-provided resource that already implements the async disposable protocol. For example, the Node.jsFileHandle is async disposable:

js
import fs from "node:fs/promises";async function example() {  await using file = await fs.open("example.txt", "r");  console.log(await file.read());  // Before `file` goes out of scope, it is disposed by calling `file[Symbol.asyncDispose]()` and awaited.}

Note that there are twoawait operations in the declaration forfile, which do different things and are both necessary.await fs.open() causes an await duringacquisition: it waits for the file to be opened and unwraps the returned promise into aFileHandle object.await using file causes an await duringdisposal: it makesfile disposed asynchronously when the variable goes out of scope.

await using withfor await...of

It's very easy to confuse the following three syntaxes:

  • for await (using x of y) { ... }
  • for (await using x of y) { ... }
  • for (using x of await y) { ... }

It may be even more confusing to know that they can be used together.

js
for await (await using x of await y) {  // ...}

First,await y does what you expect: weawait the promisey, which is expected to resolve to an object we iterate over. Let us set this variant aside.

Thefor await...of loop requires they object to be anasync iterable. This means that the object must have a[Symbol.asyncIterator] method that returns anasync iterator, whosenext() method returns a promise representing the result. This is for when the iterable doesn't know what the next value is, or even if it's done yet, until some async operation is complete.

On the other hand, theawait using x syntax requires thex object, as yielded from the iterable, to be anasync disposable. This means that the object must have a[Symbol.asyncDispose] method that returns a promise representing the disposal operation. This is a separate concern from the iteration itself, and is only called when the variablex goes out of scope.

In other words, all of the following four combinations are valid and do different things:

  • for (using x of y):y is synchronously iterated, yielding one result at a time, which can be disposed synchronously.
  • for await (using x of y):y is asynchronously iterated, yielding one result at a time after awaiting, but the result value can be disposed synchronously.
  • for (await using x of y):y is synchronously iterated, yielding one result at a time, but the result value can only be disposed asynchronously.
  • for await (await using x of y):y is asynchronously iterated, yielding one result at a time after awaiting, and the result value can only be disposed asynchronously.

Below, we create some fictitious values ofy to demonstrate their use cases. For asynchronous APIs, we base our code on the Node.jsfs/promises module.

js
const syncIterableOfSyncDisposables = [  stream1.getReader(),  stream2.getReader(),];for (using reader of syncIterableOfSyncDisposables) {  console.log(reader.read());}
js
async function* requestMany(urls) {  for (const url of urls) {    const res = await fetch(url);    yield res.body.getReader();  }}const asyncIterableOfSyncDisposables = requestMany([  "https://example.com",  "https://example.org",]);for await (using reader of asyncIterableOfSyncDisposables) {  console.log(reader.read());}
js
const syncIterableOfAsyncDisposables = await Promise.all(  fs.globSync("*.txt").map((path) => fs.open(path, "r")),);for (await using file of syncIterableOfAsyncDisposables) {  console.log(await file.read());}
js
async function* globHandles(pattern) {  for await (const path of fs.glob(pattern)) {    yield await fs.open(path, "r");  }}const asyncIterableOfAsyncDisposables = globHandles("*.txt");for await (await using file of asyncIterableOfAsyncDisposables) {  console.log(await file.read());}

Implicit await on scope exit

As soon as oneawait using is declared in a scope, the scope will always have anawait on exit, even if the variable isnull orundefined. This ensures stable execution order and error handling. TheControl flow effects of await examples have more details on this.

In the example below, theexample() call below doesn't resolve until one tick after, because of an implicitawait when the function returns.

js
async function example() {  await using nothing = null;  console.log("Example call");}example().then(() => console.log("Example done"));Promise.resolve().then(() => console.log("Microtask done"));// Output:// Example call// Microtask done// Example done

Consider the same code but with a synchronoususing instead. This time, theexample() call immediately resolves, so the twothen() handlers are called in the same tick.

js
async function example() {  using nothing = null;  console.log("Example call");}example().then(() => console.log("Example done"));Promise.resolve().then(() => console.log("Microtask done"));// Output:// Example call// Example done// Microtask done

For a more realistic example, consider two concurrent calls to a function:

js
class Resource {  #name;  constructor(name) {    this.#name = name;  }  async [Symbol.asyncDispose]() {    console.log(`Disposing resource ${this.#name}`);  }}async function example(id, createOptionalResource) {  await using required = new Resource(`required ${id}`);  await using optional = createOptionalResource    ? new Resource("optional")    : null;  await using another = new Resource(`another ${id}`);}example(1, true);example(2, false);// Output:// Disposing resource another 1// Disposing resource another 2// Disposing resource optional// Disposing resource required 1// Disposing resource required 2

As you can see, therequired 2 resource is disposed in the same tick asrequired 1. If theoptional resource did not cause a redundantawait, thenrequired 2 would have been disposed earlier, which would be simultaneous withoptional.

Specifications

Specification
ECMAScript Async Explicit Resource Management
# prod-AwaitUsingDeclaration

Browser compatibility

See also

Help improve MDN

Learn how to contribute

This page was last modified on byMDN contributors.


[8]ページ先頭

©2009-2025 Movatter.jp