[ Web Proxy ]
URL:
Viewing: https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Statements/using [Back]  [Original]

using - JavaScript | MDN

Dieser Inhalt wurde automatisch aus dem Englischen bersetzt, und kann Fehler enthalten. Erfahre mehr ber dieses Experiment.

View in English Always switch to English

using

Eingeschrnkt verfgbar

Diese Funktion ist nicht Baseline, da sie in einigen der am weitesten verbreiteten Browser nicht funktioniert.

Want more browser support for this feature? Tell us why.

Die using-Deklaration erklrt block-skopierte lokale Variablen, die synchron freigegeben werden. Wie bei const mssen Variablen, die mit using deklariert werden, initialisiert werden und knnen nicht neu zugewiesen werden. Der Wert der Variable muss entweder null, undefined oder ein Objekt mit einer [Symbol.dispose]()-Methode sein. Wenn die Variable auer Reichweite gert, wird die [Symbol.dispose]()-Methode des Objekts aufgerufen, um sicherzustellen, dass Ressourcen freigegeben werden.

In diesem Artikel

Syntax

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

Der Name der zu deklarierenden Variable. Jede muss ein gltiger JavaScript-Bezeichner sein und kein Destrukturierungs-Bindungsmuster.

valueN

Anfangswert der Variablen. Es kann jeder gltige Ausdruck sein, aber sein Wert muss entweder null, undefined oder ein Objekt mit einer [Symbol.dispose]()-Methode sein.

Beschreibung

Diese Deklaration kann verwendet werden:

Es kann nicht verwendet werden:

  • Auf der obersten Ebene eines Skripts, da Skript-Skopen persistent sind.
  • Auf der obersten Ebene einer switch-Anweisung.
  • In der Initialisierung einer for...in-Schleife. Da die Schleifenvariable nur eine Zeichenkette oder ein Symbol sein kann, ergibt dies keinen Sinn.

Ein using erklrt eine freigebbare Ressource, die mit der Lebensdauer des Skopenumfangs der Variable (Block, Funktion, Modul usw.) verbunden ist. Wenn das Skopus endet, wird die Ressource synchron freigegeben. Die Variable darf den Wert null oder undefined haben, sodass die Ressource optional vorhanden sein kann.

Wenn die Variable zuerst deklariert wird und ihr Wert nicht null ist, wird ein Disposer vom Objekt abgerufen. Wenn die [Symbol.dispose]-Eigenschaft keine Funktion enthlt, wird ein TypeError ausgelst. Dieser Disposer wird im Umfang gespeichert.

Wenn die Variable auer Reichweite gert, wird der Disposer aufgerufen. Wenn der Skopus mehrere using oder await using-Deklarationen enthlt, werden alle Disposer in umgekehrter Reihenfolge der Deklaration ausgefhrt, unabhngig von der Art der Deklaration. Alle Disposer werden garantiert ausgefhrt (hnlich wie der finally-Block in try...catch...finally). Alle whrend der Freigabe auftretenden Fehler, einschlielich des anfnglichen Fehlers, der das Skopus-Ende verursacht hat (falls zutreffend), werden alle in einem SuppressedError aggregiert, wobei jede frhere Ausnahme als suppressed-Eigenschaft und die sptere Ausnahme als error-Eigenschaft dient. Dieser SuppressedError wird geworfen, nachdem die Freigabe abgeschlossen ist.

using verknpft das Ressourcenmanagement mit lexikalischen Skopen, was sowohl praktisch als auch manchmal verwirrend ist. Es gibt viele Mglichkeiten, den Wert der Variable zu bewahren, wenn die Variable selbst auer Reichweite ist, sodass Sie mglicherweise einen Verweis auf eine bereits freigegebene Ressource halten. Unten finden Sie Beispiele, bei denen es mglicherweise nicht wie erwartet funktioniert. Wenn Sie die Freigabe von Ressourcen selbst verwalten mchten, whrend Sie die gleichen Garantien fr Fehlerbehandlung einhalten, knnen Sie stattdessen DisposableStack verwenden.

Beispiele

In den folgenden Beispielen nehmen wir eine einfache Resource-Klasse an, die eine getValue-Methode und eine [Symbol.dispose]()-Methode hat:

js
class Resource {
  value = Math.random();
  #isDisposed = false;

  getValue() {
    if (this.#isDisposed) {
      throw new Error("Resource is disposed");
    }
    return this.value;
  }

  [Symbol.dispose]() {
    this.#isDisposed = true;
    console.log("Resource disposed");
  }
}

using in einem Block

Die mit using deklarierte Ressource wird beim Verlassen des Blocks freigegeben.

js
{
  using resource = new Resource();
  console.log(resource.getValue());
  // resource disposed here
}

using in einer Funktion

Sie knnen using in einem Funktionskrper verwenden. In diesem Fall wird die Ressource freigegeben, wenn die Funktion ihre Ausfhrung beendet, unmittelbar bevor die Funktion zurckkehrt.

js
function example() {
  using resource = new Resource();
  return resource.getValue();
}

Hier wird resource[Symbol.dispose]() nach getValue(), aber bevor die return-Anweisung ausgefhrt wird, aufgerufen.

Die Ressource kann die Deklaration berleben, falls sie von einem Closure eingefangen wird:

js
function example() {
  using resource = new Resource();
  return () => resource.getValue();
}

In diesem Fall, wenn Sie example()() aufrufen, wird stets getValue auf eine Ressource ausgefhrt, die bereits freigegeben wurde, da die Ressource freigegeben wurde, als example zurckkehrte. Falls Sie die Ressource sofort nach einmaligem Aufrufen des Rckrufs freigeben mchten, erwgen Sie dieses Muster:

js
function example() {
  const resource = new Resource();
  return () => {
    using resource2 = resource;
    return resource2.getValue();
  };
}

Hier, wir aliasen eine mit const deklarierte Ressource zu einer mit using deklarierten Ressource, sodass die Ressource erst nach dem Aufruf des Rckrufs freigegeben wird; beachten Sie, dass die Ressource niemals bereinigt wird, wenn sie nie aufgerufen wird.

using in einem Modul

Sie knnen using auf der obersten Ebene eines Moduls verwenden. In diesem Fall wird die Ressource freigegeben, wenn das Modul die Ausfhrung beendet.

js
using resource = new Resource();
export const value = resource.getValue();
// resource disposed here

export using ist ungltige Syntax, aber Sie knnen eine anderswo mit using deklarierte Variable exportieren:

js
using resource = new Resource();
export { resource };

Dies wird dennoch abgeraten, da der Importeur immer eine freigegebene Ressource erhlt. hnlich wie beim Closure-Problem fhrt dies dazu, dass der Wert der Ressource lnger besteht als die Variable.

using mit for...of

Sie knnen using in der Initialisierung einer for...of-Schleife verwenden. In diesem Fall wird die Ressource in jeder Schleifeniteration freigegeben.

js
const resources = [new Resource(), new Resource(), new Resource()];
for (using resource of resources) {
  console.log(resource.getValue());
  // resource disposed here
}

Mehrere using

Die folgenden sind zwei gleichwertige Mglichkeiten, mehrere freigebbare Ressourcen zu deklarieren:

js
using resource1 = new Resource(),
  resource2 = new Resource();

// OR

using resource1 = new Resource();
using resource2 = new Resource();

In beiden Fllen wird, wenn das Skop endet, resource2 vor resource1 freigegeben. Dies liegt daran, dass resource2 mglicherweise von resource1 abhngt, daher wird es zuerst freigegeben, um sicherzustellen, dass resource1 noch verfgbar ist, wenn resource2 freigegeben wird.

Optional using

using erlaubt der Variable, einen Wert von null oder undefined zu haben, sodass die Ressource optional vorhanden sein kann. Dies bedeutet, dass Sie beispielsweise bei der berprfung der Verfgbarkeit einer Ressource irgendeiner Art:

js
function acquireResource() {
  // Imagine some real-world relevant condition here,
  // such as whether there's space to allocate for this resource
  if (Math.random() < 0.5) {
    return null;
  }
  return new Resource();
}

nicht tun mssen:

js
const maybeResource = acquireResource();

if (maybeResource) {
  using resource = maybeResource;
  console.log(resource.getValue());
} else {
  console.log(undefined);
}

Stattdessen knnen Sie dies tun:

js
using resource = acquireResource();
console.log(resource?.getValue());

using-Deklaration ohne Verwendung der Variable

Sie knnen automatisches Freigeben von Ressourcen mit using erreichen, ohne die Variable zu verwenden. Dies ist sehr ntzlich, um einen Kontext innerhalb eines Blocks einzurichten, wie das Erstellen einer Sperre:

js
{
  using _ = new Lock();
  // Perform concurrent operations here
  // Lock disposed (released) here
}

Beachten Sie, dass _ ein normaler Bezeichner ist, jedoch konventionell als "Wegwerf"-Variable verwendet wird. Um mehrere ungenutzte Variablen zu erstellen, mssen Sie unterschiedliche Namen verwenden, z.B. indem Sie einen Variablennamen mit _ voranstellen.

Initialisierung und temporale tote Zonen

using-Variablen unterliegen den gleichen temporal dead zone-Einschrnkungen wie let- und const-Variablen. Das bedeutet, dass Sie nicht auf die Variable zugreifen knnen, bevor sie initialisiert istdie gltige Lebensdauer der Ressource reicht strikt von der Initialisierung bis zum Ende ihres Skopos. Dies ermglicht RAII-hnliches Ressourcenmanagement.

js
let useResource;
{
  useResource = () => resource.getValue();
  useResource(); // Error: Cannot access 'resource' before initialization
  using resource = new Resource();
  useResource(); // Valid
}
useResource(); // Error: Resource is disposed

Fehlerbehandlung

Die using-Deklaration ist am ntzlichsten fr das Verwalten der Ressourcenfreigabe bei Vorhandensein von Fehlern. Wenn Sie nicht vorsichtig sind, knnen einige Ressourcen auslaufen, weil der Fehler das nachfolgende Ausfhren von Code verhindert.

js
function handleResource(resource) {
  if (resource.getValue() > 0.5) {
    throw new Error("Resource value too high");
  }
}

try {
  using resource = new Resource();
  handleResource(resource);
} catch (e) {
  console.error(e);
}

Dies wird den von handleResource ausgelsten Fehler erfolgreich abfangen und protokollieren, und unabhngig davon, ob handleResource einen Fehler auslst oder nicht, wird die Ressource vor dem Verlassen des try-Blocks freigegeben.

Hier, wenn Sie using nicht verwenden, knnten Sie so etwas tun:

js
try {
  const resource = new Resource();
  handleResource(resource);
  resource[Symbol.dispose]();
} catch (e) {
  console.error(e);
}

Wenn jedoch handleResource() einen Fehler auslst, erreicht die Kontrolle niemals resource[Symbol.dispose](), und die Ressource wird nicht freigegeben. Darber hinaus knnen Fehler, die beim Freigeben frherer Ressourcen auftreten, verhindern, dass spter freigegebene Ressourcen ausgefhrt werden, was zu weiteren Lecks fhrt.

Betrachten Sie einen komplizierteren Fall, bei dem der Disposer selbst einen Fehler auslst:

js
class CantDisposeMe {
  #name;
  constructor(name) {
    this.#name = name;
  }
  [Symbol.dispose]() {
    throw new Error(`Can't dispose ${this.#name}`);
  }
}

let error;

try {
  using resource1 = new CantDisposeMe("resource1");
  using resource2 = new CantDisposeMe("resource2");
  throw new Error("Error in main block");
} catch (e) {
  error = e;
}

Sie knnen den in der Konsole Ihres Browsers geworfenen Fehler untersuchen. Er hat folgende Struktur:

SuppressedError: An error was suppressed during disposal
  suppressed: SuppressedError: An error was suppressed during disposal
    suppressed: Error: Can't dispose resource1
    error: Error: Error in main block
  error: Error: Can't dispose resource2

Wie Sie sehen, enthlt error alle whrend der Freigabe geworfenen Fehler als SuppressedError. Jeder zustzliche Fehler wird als die error-Eigenschaft hinzugefgt, und der ursprngliche Fehler wird als die suppressed-Eigenschaft hinzugefgt.

Spezifikationen

Spezifikation
ECMAScript Async Explicit Resource Management
# prod-UsingDeclaration

Browser-Kompatibilitt

Siehe auch


Web Proxy Viewer  |  New URL  |  Original Page