Signatur
Beschreibung
Der await-Operator wird verwendet, um auf ein Promise zu warten und seinen Erfüllungswert (fulfillment value) zu erhalten. Er kann nur innerhalb einer async function oder auf oberster Ebene eines Modules verwendet werden.
await wird üblicherweise verwendet, um Promises zu entpacken, indem ein Promise als expression übergeben wird. Die Verwendung von await pausiert die Ausführung der umgebenden async-Funktion, bis das Promise abgeschlossen (settled) ist (also entweder fulfilled oder rejected). Wenn die Ausführung fortgesetzt wird, entspricht der Wert des await-Ausdrucks dem des erfüllten Promise.
Wenn das Promise rejected wird, wirft der await-Ausdruck den zurückgewiesenen Wert. Die Funktion, die den await-Ausdruck enthält, erscheint im Stack-Trace des Fehlers. Andernfalls, wenn das rejected Promise nicht awaited oder sofort zurückgegeben wird, erscheint die aufrufende Funktion nicht im Stack-Trace.
Der expression wird auf die gleiche Weise aufgelöst wie Promise.resolve(): Er wird immer in ein natives Promise konvertiert und dann awaited. Wenn expression Folgendes ist:
- Natives
Promise(das bedeutet,expressiongehört zuPromiseoder einer Subklasse, undexpression.constructor === Promise): Das Promise wird direkt verwendet und nativ awaited, ohnethen()aufzurufen. - Thenable object (einschließlich nicht-nativer Promises, Polyfill, Proxy, Kindklasse usw.): Ein neues Promise wird mit dem nativen
Promise()-Konstruktor erstellt, indem diethen()-Methode des Objekts aufgerufen und ein Handler übergeben wird, der denresolve-callback aufruft. - Nicht-thenable Wert: Ein bereits erfülltes
Promisewird erstellt und verwendet.
Selbst wenn das verwendete Promise bereits fulfilled ist, pausiert die Ausführung der async function trotzdem bis zum nächsten Tick. In der Zwischenzeit setzt der Aufrufer der async function die Ausführung fort.
Da await nur innerhalb von async functions und Modulen gültig ist, welche selbst asynchron sind und Promises zurückgeben, blockiert der await-Ausdruck niemals den Main-Thread und verzögert nur die Ausführung von Code, der tatsächlich vom Ergebnis abhängt, d. h. alles nach dem await-Ausdruck.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $expression Pflicht | Promise | thenable | any | — | Ein Promise, ein thenable object oder ein beliebiger Wert, auf den gewartet werden soll. |
Rückgabewert
Beispiele
Auf die Erfüllung eines Promise warten
function resolveAfter2Seconds(x) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}
async function f1() {
const x = await resolveAfter2Seconds(10);
console.log(x); // 10
}
f1();
Thenable objects
async function f2() {
const thenable = {
then(resolve) {
resolve("resolved!");
},
};
console.log(await thenable); // "resolved!"
}
f2();
Thenable, das rejected wird
async function f2() {
const thenable = {
then(_, reject) {
reject(new Error("rejected!"));
},
};
await thenable; // Throws Error: rejected!
}
f2();
Konvertierung zu Promise
async function f3() {
const y = await 20;
console.log(y); // 20
const obj = {};
console.log((await obj) === obj); // true
}
f3();
Umgang mit rejected Promises
async function f4() {
try {
const z = await Promise.reject(new Error("rejected!"));
} catch (e) {
console.error(e); // Error: rejected!
}
}
f4();
Fehlerbehandlung mit catch()
const response = await promisedFunction().catch((err) => {
console.error(err);
return "default response";
});
// response will be "default response" if the promise is rejected
Top level await
// fetch request
const colors = fetch("../data/colors.json").then((response) => response.json());
export default await colors;
Kontrollfluss ohne await (synchron)
async function foo(name) {
console.log(name, "start");
console.log(name, "middle");
console.log(name, "end");
}
foo("First");
foo("Second");
// First start
// First middle
// First end
// Second start
// Second middle
// Second end
Kontrollfluss mit await
async function foo(name) {
console.log(name, "start");
await console.log(name, "middle");
console.log(name, "end");
}
foo("First");
foo("Second");
// First start
// First middle
// Second start
// Second middle
// First end
// Second end
Microtask-Reihenfolge
let i = 0;
queueMicrotask(function test() {
i++;
console.log("microtask", i);
if (i < 3) {
queueMicrotask(test);
}
});
(async () => {
console.log("async function start");
for (let i = 1; i < 3; i++) {
await null;
console.log("async function resume", i);
}
await null;
console.log("async function end");
})();
queueMicrotask(() => {
console.log("queueMicrotask() after calling async function");
});
console.log("script sync part end");
// Logs:
// async function start
// script sync part end
// microtask 1
// async function resume 1
// queueMicrotask() after calling async function
// microtask 2
// async function resume 2
// microtask 3
// async function end
Stack-Trace ohne await
async function lastAsyncTask() {
await null;
throw new Error("failed");
}
async function noAwait() {
return lastAsyncTask();
}
noAwait();
// Error: failed
// at lastAsyncTask
Verbesserter Stack-Trace mit return await
async function lastAsyncTask() {
await null;
throw new Error("failed");
}
async function withAwait() {
return await lastAsyncTask();
}
withAwait();
// Error: failed
// at lastAsyncTask
// at async withAwait
// Wichtig · Fallstricke
Entgegen einer weit verbreiteten Ansicht ist return await promise mindestens so schnell wie return promise, aufgrund der Art und Weise, wie die Spezifikation und Engines die Auflösung nativer Promises optimieren. Daher ist return await — abgesehen von stilistischen Gründen — fast immer vorzuziehen.