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
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:
async function foo() {
return 1;
}
Er ist ähnlich wie:
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.
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:
async function foo() {
await 1;
}
Es ist auch gleichwertig zu:
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.
- 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 durchfoo
wird dann ausgesetzt und die Kontrolle wird an die Funktion zurückgegeben, diefoo
aufgerufen hat. - 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 wird1
anresult1
zugewiesen. Der Fortschritt geht weiter, und der zweite await-Ausdruck wird ausgewertet. Wieder wird der Fortschritt durchfoo
ausgesetzt und die Kontrolle übergeben. - 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 wird2
anresult2
zugewiesen. Die Kontrolle bewegt sich zum Rückgabewert-Ausdruck (falls vorhanden). Der Standard Rückgabewert vonundefined
wird als Auflösungswert des aktuellen Promises zurückgegeben.
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.
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
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 await
ed.
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:
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:
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:
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
- Funktionen Leitfaden
- Verwendung von Promises Leitfaden
- Funktionen
AsyncFunction
async function
Ausdruckfunction
function*
async function*
await
Promise
- Dekorieren von asynchronen JavaScript-Funktionen auf innolitics.com (2016)