async function

Baseline Widely available

This feature is well established and works across many devices and browser versions. It’s been available across browsers since April 2017.

Die async function Deklaration erzeugt eine Bindung einer neuen asynchronen Funktion an einen gegebenen Namen. Das await Schlüsselwort ist innerhalb des Funktionskörpers erlaubt, was ermöglicht, asynchrones, auf Promises basierendes Verhalten in einem klareren Stil zu schreiben und die Notwendigkeit zu vermeiden, Promise-Ketten explizit zu konfigurieren.

Sie können auch asynchrone Funktionen mit dem async function Ausdruck definieren.

Probieren Sie es aus

function resolveAfter2Seconds() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve("resolved");
    }, 2000);
  });
}

async function asyncCall() {
  console.log("calling");
  const result = await resolveAfter2Seconds();
  console.log(result);
  // Expected output: "resolved"
}

asyncCall();

Syntax

js
async function name(param0) {
  statements
}
async function name(param0, param1) {
  statements
}
async function name(param0, param1, /* …, */ paramN) {
  statements
}

Hinweis: Es darf keinen Zeilenumbruch zwischen async und function geben, da ansonsten ein Semikolon automatisch eingefügt wird, was dazu führt, dass async zu einem Bezeichner wird und der Rest zu einer function Deklaration.

Parameter

name

Der Name der Funktion.

param Optional

Der Name eines formalen Parameters für die Funktion. Für die Syntax der Parameter siehe das Funktionen-Referenzdokument.

statements Optional

Die Anweisungen, die den Körper der Funktion bilden. Der await Mechanismus kann verwendet werden.

Beschreibung

Eine async function Deklaration erstellt ein AsyncFunction Objekt. Jedes Mal, wenn eine asynchrone Funktion aufgerufen wird, wird ein neues Promise zurückgegeben, das mit dem von der asynchronen Funktion zurückgegebenen Wert aufgelöst oder mit einer Ausnahme abgelehnt wird, die innerhalb der asynchronen Funktion nicht abgefangen wurde.

Asynchrone Funktionen können null oder mehr await Ausdrücke enthalten. Await-Ausdrücke lassen Funktionen, die Promises zurückgeben, so verhalten, als ob sie synchron sind, indem sie die Ausführung aussetzen, bis das zurückgegebene Promise erfüllt oder abgelehnt wird. Der aufgelöste Wert des Promises wird als Rückgabewert des await-Ausdrucks behandelt. Der Gebrauch von async und await ermöglicht die Verwendung von gewöhnlichen try / catch Blöcken um asynchronen Code.

Hinweis: Das Schlüsselwort await ist nur innerhalb von asynchronen Funktionen im regulären JavaScript-Code gültig. Wenn Sie es außerhalb des Körpers einer asynchronen Funktion verwenden, erhalten Sie einen SyntaxError.

await kann allein mit JavaScript-Modulen verwendet werden.

Hinweis: Der Zweck von async/await ist es, die Syntax zu vereinfachen, die notwendig ist, um auf Promise-basierte APIs zuzugreifen. Das Verhalten von async/await ähnelt der Kombination von Generatoren und Promises.

Asynchrone Funktionen geben immer ein Promise zurück. Wenn der Rückgabewert einer asynchronen Funktion nicht ausdrücklich ein Promise ist, wird er implizit in ein Promise eingebettet.

Betrachten Sie zum Beispiel den folgenden Code:

js
async function foo() {
  return 1;
}

Er ist ähnlich wie:

js
function foo() {
  return Promise.resolve(1);
}

Beachten Sie, dass, auch wenn der Rückgabewert einer asynchronen Funktion sich so verhält, als ob er in einem Promise.resolve eingebettet ist, sie nicht gleichwertig sind. Eine asynchrone Funktion gibt einen anderen Referenzwert zurück, während Promise.resolve denselben Referenzwert zurückgibt, wenn der gegebene Wert ein Promise ist. Dies kann ein Problem sein, wenn Sie die Gleichheit eines Promises und eines Rückgabewerts einer asynchronen Funktion überprüfen möchten.

js
const p = new Promise((res, rej) => {
  res(1);
});

async function asyncReturn() {
  return p;
}

function basicReturn() {
  return Promise.resolve(p);
}

console.log(p === basicReturn()); // true
console.log(p === asyncReturn()); // false

Der Körper einer asynchronen Funktion kann als in null oder mehr await-Ausdrücke unterteilt betrachtet werden. Top-Level-Code, bis hin zum ersten await-Ausdruck (falls vorhanden), wird synchron ausgeführt. Auf diese Weise wird eine asynchrone Funktion ohne await-Ausdruck synchron ausgeführt. Wenn jedoch ein await-Ausdruck im Funktionskörper vorhanden ist, wird die asynchrone Funktion immer asynchron abgeschlossen.

Zum Beispiel:

js
async function foo() {
  await 1;
}

Es ist auch gleichwertig zu:

js
function foo() {
  return Promise.resolve(1).then(() => undefined);
}

Code nach jedem await-Ausdruck kann als im .then-Callback bestehend betrachtet werden. Auf diese Weise wird eine Promise-Kette schrittweise aufgebaut, mit jedem erneuten Schritt durch die Funktion. Der Rückgabewert bildet das letzte Glied in der Kette.

Im folgenden Beispiel erwarten wir nacheinander zwei Promises. Der Fortschritt durchläuft die Funktion foo in drei Phasen.

  1. Die erste Zeile des Körpers der Funktion foo wird synchron ausgeführt, mit dem await-Ausdruck, der mit dem ausstehenden Promise konfiguriert ist. Der Fortschritt durch foo wird dann ausgesetzt und die Kontrolle wird an die Funktion zurückgegeben, die foo aufgerufen hat.
  2. Einige Zeit später, wenn das erste Promise entweder erfüllt oder abgelehnt wurde, bewegt sich die Kontrolle zurück in foo. Das Ergebnis der ersten Promise-Erfüllung (wenn es nicht abgelehnt wurde) wird aus dem await-Ausdruck zurückgegeben. Hier wird 1 an result1 zugewiesen. Der Fortschritt geht weiter, und der zweite await-Ausdruck wird ausgewertet. Wieder wird der Fortschritt durch foo ausgesetzt und die Kontrolle übergeben.
  3. Einige Zeit später, wenn das zweite Promise entweder erfüllt oder abgelehnt wurde, tritt die Kontrolle wieder in foo ein. Das Ergebnis der zweiten Promise-Auflösung wird aus dem zweiten await-Ausdruck zurückgegeben. Hier wird 2 an result2 zugewiesen. Die Kontrolle bewegt sich zum Rückgabewert-Ausdruck (falls vorhanden). Der Standard Rückgabewert von undefined wird als Auflösungswert des aktuellen Promises zurückgegeben.
js
async function foo() {
  const result1 = await new Promise((resolve) =>
    setTimeout(() => resolve("1")),
  );
  const result2 = await new Promise((resolve) =>
    setTimeout(() => resolve("2")),
  );
}
foo();

Beachten Sie, wie die Promise-Kette nicht auf einmal aufgebaut wird. Stattdessen wird die Promise-Kette in Stufen aufgebaut, wenn die Kontrolle nacheinander von der asynchronen Funktion gegeben und wieder übernommen wird. Daher müssen wir beim Umgang mit gleichzeitigen asynchronen Operationen das Fehlerverhalten beachten.

Zum Beispiel, im folgenden Code wird ein unbehandelter Promise-Ablehnungsfehler ausgelöst, selbst wenn ein .catch-Handler weiter entlang der Promise-Kette konfiguriert wurde. Das liegt daran, dass p2 nicht in die Promise-Kette "eingebunden" wird, bis die Kontrolle von p1 zurückkehrt.

js
async function foo() {
  const p1 = new Promise((resolve) => setTimeout(() => resolve("1"), 1000));
  const p2 = new Promise((_, reject) => setTimeout(() => reject("2"), 500));
  const results = [await p1, await p2]; // Do not do this! Use Promise.all or Promise.allSettled instead.
}
foo().catch(() => {}); // Attempt to swallow all errors...

async function Deklarationen verhalten sich ähnlich wie function Deklarationen — sie werden gehoistet an den Anfang ihres Scopes und können überall in ihrem Scope aufgerufen werden, und sie können nur in bestimmten Kontexten erneut deklariert werden.

Beispiele

Asynchrone Funktionen und Ausführungsreihenfolge

js
function resolveAfter2Seconds() {
  console.log("starting slow promise");
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve("slow");
      console.log("slow promise is done");
    }, 2000);
  });
}

function resolveAfter1Second() {
  console.log("starting fast promise");
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve("fast");
      console.log("fast promise is done");
    }, 1000);
  });
}

async function sequentialStart() {
  console.log("== sequentialStart starts ==");

  // 1. Start a timer, log after it's done
  const slow = resolveAfter2Seconds();
  console.log(await slow);

  // 2. Start the next timer after waiting for the previous one
  const fast = resolveAfter1Second();
  console.log(await fast);

  console.log("== sequentialStart done ==");
}

async function sequentialWait() {
  console.log("== sequentialWait starts ==");

  // 1. Start two timers without waiting for each other
  const slow = resolveAfter2Seconds();
  const fast = resolveAfter1Second();

  // 2. Wait for the slow timer to complete, and then log the result
  console.log(await slow);
  // 3. Wait for the fast timer to complete, and then log the result
  console.log(await fast);

  console.log("== sequentialWait done ==");
}

async function concurrent1() {
  console.log("== concurrent1 starts ==");

  // 1. Start two timers concurrently and wait for both to complete
  const results = await Promise.all([
    resolveAfter2Seconds(),
    resolveAfter1Second(),
  ]);
  // 2. Log the results together
  console.log(results[0]);
  console.log(results[1]);

  console.log("== concurrent1 done ==");
}

async function concurrent2() {
  console.log("== concurrent2 starts ==");

  // 1. Start two timers concurrently, log immediately after each one is done
  await Promise.all([
    (async () => console.log(await resolveAfter2Seconds()))(),
    (async () => console.log(await resolveAfter1Second()))(),
  ]);
  console.log("== concurrent2 done ==");
}

sequentialStart(); // after 2 seconds, logs "slow", then after 1 more second, "fast"

// wait above to finish
setTimeout(sequentialWait, 4000); // after 2 seconds, logs "slow" and then "fast"

// wait again
setTimeout(concurrent1, 7000); // same as sequentialWait

// wait again
setTimeout(concurrent2, 10000); // after 1 second, logs "fast", then after 1 more second, "slow"

await und Parallelität

In sequentialStart wird die Ausführung für 2 Sekunden für das erste await ausgesetzt und dann eine weitere Sekunde für das zweite await. Der zweite Timer wird nicht erstellt, bis der erste bereits ausgelöst wurde, sodass der Code nach 3 Sekunden endet.

In sequentialWait werden beide Timer erstellt und dann awaited. Die Timer laufen parallel, was bedeutet, dass der Code in 2 anstatt 3 Sekunden endet, d.h. der langsamste Timer. Die await-Aufrufe laufen jedoch immer noch in Serie, was bedeutet, dass das zweite await auf das Ende des ersten wartet. In diesem Fall wird das Ergebnis des schnellsten Timers nach dem langsamsten verarbeitet.

Wenn Sie sicher andere Aufgaben nach zwei oder mehr gleichzeitig laufenden und abgeschlossenen Aufgaben ausführen möchten, müssen Sie einen Aufruf von Promise.all() oder Promise.allSettled() abwarten, bevor Sie diese Aufgabe ausführen.

Warnung: Die Funktionen sequentialWait und concurrent1 sind nicht funktional äquivalent.

In sequentialWait, wenn das Promise fast abgelehnt wird, bevor das Promise slow erfüllt ist, wird ein unbehandelter Promise-Ablehnungsfehler ausgelöst, unabhängig davon, ob der Aufrufer eine Catch-Anweisung konfiguriert hat oder nicht.

In concurrent1, verdrahtet Promise.all die Promise Kette auf einmal, was bedeutet, dass die Operation bei schnellstem Fehler scheitert, unabhängig von der Ablehnungsreihenfolge der Promises, und der Fehler wird immer innerhalb der konfigurierten Promise-Kette auftreten, sodass er auf normale Weise abgefangen werden kann.

Umschreiben einer Promise-Kette mit einer asynchronen Funktion

Eine API, die eine Promise zurückgibt, resultiert in einer Promise-Kette, und sie teilt die Funktion in viele Teile. Betrachten Sie den folgenden Code:

js
function getProcessedData(url) {
  return downloadData(url) // returns a promise
    .catch((e) => downloadFallbackData(url)) // returns a promise
    .then((v) => processDataInWorker(v)); // returns a promise
}

er kann mit einer einzigen asynchronen Funktion wie folgt umgeschrieben werden:

js
async function getProcessedData(url) {
  let v;
  try {
    v = await downloadData(url);
  } catch (e) {
    v = await downloadFallbackData(url);
  }
  return processDataInWorker(v);
}

Alternativ können Sie das Promise mit catch() verketten:

js
async function getProcessedData(url) {
  const v = await downloadData(url).catch((e) => downloadFallbackData(url));
  return processDataInWorker(v);
}

In den beiden umgeschriebenen Versionen beachten Sie, dass es keine await-Anweisung nach dem return Schlüsselwort gibt, obwohl das auch gültig wäre: Der Rückgabewert einer asynchronen Funktion wird implizit in Promise.resolve eingebettet - wenn er nicht bereits ein Promise selbst ist (wie in den Beispielen).

Spezifikationen

Specification
ECMAScript® 2025 Language Specification
# sec-async-function-definitions

Browser-Kompatibilität

BCD tables only load in the browser

Siehe auch