Start · Sprachen · JavaScript · Referenz · using

using

Anweisung

Deklariert eine block-skopierte Variable, deren <code>Symbol.dispose</code>-Methode am Ende des Blocks <em>synchron</em> aufgerufen wird.

seit JavaScript ES2026 (Stage-3-Proposal; V8/Chrome 134+, Firefox Kategorie: syntax

Signatur

using identifier = expression

Beschreibung

using ist eine neue Deklarationsform ähnlich const, die Ressourcen-Management direkt in die Sprache integriert. Wird der Block verlassen – egal ob normal, per return, break, throw oder continue –, ruft die JavaScript-Runtime automatisch die Methode [Symbol.dispose]() des gebundenen Objekts auf. Das schließt Dateien, Datenbankverbindungen, Locks, Streams und andere Ressourcen zuverlässig, ohne dass ein try/finally-Block von Hand geschrieben werden muss.

Eine mit using deklarierte Variable verhält sich in Bezug auf Sichtbarkeit wie const: Sie ist block-skopiert, nicht hoisted (Temporal Dead Zone gilt), und darf nach der Deklaration nicht neu zugewiesen werden. Der Wert muss entweder null, undefined oder ein Objekt mit einer [Symbol.dispose]-Methode sein – andernfalls wird ein TypeError geworfen. Bei null oder undefined wird dispose stillschweigend übersprungen.

Mehrere using-Deklarationen im selben Block werden in umgekehrter Reihenfolge ihrer Deklaration freigegeben (LIFO – Last In, First Out), analog zu einem Stack von finally-Blöcken. Wirft eine dispose-Methode selbst eine Exception, wird diese mit eventuellen früheren Fehlern zu einem SuppressedError zusammengefasst, sodass keine Fehlerinformation verloren geht.

Für asynchrone Ressourcen (z. B. Datenbankverbindungen mit asynchronem Schließen) existiert die Gegenstück-Deklaration await using, die [Symbol.asyncDispose] aufruft und daher in async-Funktionen verwendet werden muss.

Parameter

Name Typ Default Beschreibung
$identifier Pflicht string Name der zu deklarierenden Variable. Bindungsregeln wie bei const: block-skopiert, keine Neuzuweisung.
$expression Pflicht object | null | undefined Ausdruck, der ausgewertet wird. Muss null, undefined oder ein Objekt mit einer [Symbol.dispose]-Methode sein. Jeder andere Wert wirft sofort einen TypeError.

Rückgabewert

Typ
void
Beschreibung
Eine Deklarations-Anweisung gibt keinen Wert zurück.

Beispiele

Eigene Ressource mit Symbol.dispose

class DatabaseConnection {
  #name;
  constructor(name) {
    this.#name = name;
    console.log(`[${this.#name}] Verbindung geöffnet`);
  }

  query(sql) {
    console.log(`[${this.#name}] Abfrage: ${sql}`);
    return [{ id: 1 }];
  }

  [Symbol.dispose]() {
    console.log(`[${this.#name}] Verbindung geschlossen`);
  }
}

function fetchUsers() {
  using db = new DatabaseConnection('primary');
  const users = db.query('SELECT * FROM users');
  console.log('Gefunden:', users.length, 'Nutzer');
  // db[Symbol.dispose]() wird hier automatisch aufgerufen
}

fetchUsers();
[primary] Verbindung geöffnet [primary] Abfrage: SELECT * FROM users Gefunden: 1 Nutzer [primary] Verbindung geschlossen

LIFO-Reihenfolge bei mehreren using-Deklarationen

const makeResource = (name) => ({
  [Symbol.dispose]() {
    console.log(`Freigabe: ${name}`);
  }
});

{
  using a = makeResource('A');
  using b = makeResource('B');
  using c = makeResource('C');
  console.log('Block wird verlassen…');
}
// Freigabe in umgekehrter Reihenfolge (LIFO)
Block wird verlassen… Freigabe: C Freigabe: B Freigabe: A

Fehler-Handling mit SuppressedError

const faultyResource = {
  [Symbol.dispose]() {
    throw new Error('Fehler beim Schließen');
  }
};

try {
  using res = faultyResource;
  throw new Error('Fehler im Block');
} catch (err) {
  // err ist ein SuppressedError
  console.log(err instanceof SuppressedError); // true
  console.log('Primärer Fehler:', err.error.message);
  console.log('Unterdrückter Fehler:', err.suppressed.message);
}
true Primärer Fehler: Fehler beim Schließen Unterdrückter Fehler: Fehler im Block

Verwendung mit DisposableStack

// DisposableStack bündelt mehrere Ressourcen in einem Stack
const openFile  = (path) => ({ path, [Symbol.dispose]() { console.log(`Datei geschlossen: ${this.path}`); } });
const acquireLock = (id)  => ({ id,   [Symbol.dispose]() { console.log(`Lock freigegeben: ${this.id}`); } });

function processFile(path) {
  using stack = new DisposableStack();
  const file = stack.use(openFile(path));
  const lock = stack.use(acquireLock('file-lock-42'));

  console.log(`Verarbeite: ${file.path} mit Lock ${lock.id}`);
  // Beim Verlassen der Funktion: Lock zuerst, dann Datei
}

processFile('/data/report.csv');
Verarbeite: /data/report.csv mit Lock file-lock-42 Lock freigegeben: file-lock-42 Datei geschlossen: /data/report.csv

// Wichtig · Fallstricke

Browser- und Laufzeit-Unterstützung: using ist Teil des TC39-Proposals „Explicit Resource Management" (Stage 3 → Stage 4 in ES2026). Natives Support besteht ab Chrome/V8 134+, Node.js 22+ (mit Flag --harmony-explicit-resource-management ab v20) sowie Deno 1.40+. Firefox und Safari unterstützen es noch nicht nativ (Stand: Mitte 2025). TypeScript transpiliert using ab Version 5.2.

  • Kein var-Äquivalent: using ist immer block-skopiert; ein function-skopiertes Pendant existiert nicht.
  • Kein Destructuring: using { a, b } = … ist nicht erlaubt. Die Deklaration bindet immer genau eine Variable.
  • null / undefined sind erlaubtdispose wird dann stillschweigend übersprungen. Alle anderen primitiven Werte (number, string, …) werfen einen TypeError.
  • Reihenfolge der Bereinigung: Mehrere using-Deklarationen werden in LIFO-Reihenfolge aufgelöst, genau wie verschachtelte finally-Blöcke.
  • Asynchrone Variante: Für Ressourcen, die asynchrones Schließen benötigen ([Symbol.asyncDispose]), muss await using innerhalb einer async-Funktion verwendet werden.
  • SuppressedError: Wirft sowohl der Block als auch ein dispose-Aufruf, werden beide Fehler in einem SuppressedError gebündelt (error = neuerer Fehler, suppressed = älterer).