for await...of
Baseline
Weitgehend verfügbar
Diese Funktion ist gut etabliert und funktioniert auf vielen Geräten und in vielen Browserversionen. Sie ist seit Januar 2020 browserübergreifend verfügbar.
Der for await...of-Ausdruck erstellt eine Schleife, die über asynchrone iterierbare Objekte sowie über synchrone Iterables iteriert. Dieser Ausdruck kann nur in Kontexten verwendet werden, in denen await eingesetzt werden kann, was den Körper einer asynchronen Funktion und ein Modul einschlieÃt.
Probieren Sie es aus
async function* foo() {
yield 1;
yield 2;
}
(async () => {
for await (const num of foo()) {
console.log(num);
// Expected output: 1
break; // Closes iterator, triggers return
}
})();
Syntax
for await (variable of iterable)
statement
variable-
Empfängt bei jeder Iteration einen Wert aus der Sequenz. Kann entweder eine Deklaration mit
const,letodervarsein oder ein Zuweisungsziel (z.B. eine zuvor deklarierte Variable, eine Objekteigenschaft oder ein Destrukturierungsmuster). Mitvardeklarierte Variablen sind nicht lokal zur Schleife, d.h. sie befinden sich im selben Gültigkeitsbereich, in dem diefor await...of-Schleife ist. iterable-
Ein asynchrones oder synchrones iterables Objekt. Quelle der Wertsequenz, auf der die Schleife operiert.
statement-
Ein Befehl, der bei jeder Iteration ausgeführt wird. Kann
variablereferenzieren. Sie können eine Blockanweisung verwenden, um mehrere Anweisungen auszuführen.
Beschreibung
Wenn eine for await...of-Schleife über ein Iterable iteriert, erhält sie zunächst die [Symbol.asyncIterator]()-Methode des Iterables und ruft sie auf, was einen asynchronen Iterator zurückgibt. Falls die @asyncIterator-Methode nicht existiert, sucht sie nach einer [Symbol.iterator]()-Methode, die einen synchronen Iterator zurückgibt. Der zurückgegebene synchrone Iterator wird dann in einen asynchronen Iterator umgewandelt, indem jedes von den Methoden next(), return() und throw() zurückgegebene Objekt in ein erfülltes oder abgelehntes Promise umgewandelt wird, wobei die value-Eigenschaft aufgelöst wird, wenn sie ebenfalls ein Promise ist. Die Schleife ruft dann wiederholt die next()-Methode des endgültigen asynchronen Iterators auf und wartet auf das zurückgegebene Promise, um die Wertsequenz zu erzeugen, die der variable zugewiesen wird.
Eine for await...of-Schleife wird beendet, wenn der Iterator abgeschlossen ist (das erwartete next()-Ergebnis ist ein Objekt mit done: true). Wie bei anderen Schleifenanweisungen können Sie Kontrollflussanweisungen innerhalb des statement verwenden:
breakstoppt die Ausführung vonstatementund geht zur ersten Anweisung nach der Schleife.continuestoppt die Ausführung vonstatementund fährt mit der nächsten Iteration der Schleife fort.
Wenn die for await...of-Schleife vorzeitig beendet wurde (z.B. wenn eine break-Anweisung auftritt oder ein Fehler ausgelöst wird), wird die return()-Methode des Iterators aufgerufen, um eine Bereinigung durchzuführen. Das zurückgegebene Promise wird erwartet, bevor die Schleife beendet wird.
for await...of funktioniert im Allgemeinen ähnlich wie die for...of-Schleife und teilt viele der gleichen Syntax und Semantik. Es gibt jedoch einige Unterschiede:
for await...offunktioniert sowohl mit synchronen als auch mit asynchronen Iterables, währendfor...ofnur mit synchronen Iterables funktioniert.for await...ofkann nur in Kontexten verwendet werden, in denenawaitverwendet werden kann, was den Körper einer asynchronen Funktion und ein Modul einschlieÃt. Selbst wenn das Iterable synchron ist, wartet die Schleife dennoch auf den Rückgabewert für jede Iteration, was aufgrund des wiederholten Promise-Abrufens zu einer langsameren Ausführung führt.- Wenn das
iterableein synchrones Iterable ist, das Promises erzeugt, würdefor await...ofeine Sequenz von aufgelösten Werten erzeugen, währendfor...ofeine Sequenz von Promises erzeugen würde. - Bei
for await...ofkann dievariableder Bezeichnerasyncsein (z.B.for await (async of foo));for...ofverbietet diesen Fall.
Wie bei for...of, wenn Sie eine using-Deklaration verwenden, darf die Variable nicht of genannt werden:
for await (using of of []); // SyntaxError
Dies ist, um Syntaxambiguität mit dem gültigen Code for await (using of []) zu vermeiden, bevor using eingeführt wurde.
Beispiele
>Iteration über asynchrone Iterables
Sie können auch über ein Objekt iterieren, das das asynchrone Iterierbare-Protokoll explizit implementiert:
const LIMIT = 3;
const asyncIterable = {
[Symbol.asyncIterator]() {
let i = 0;
return {
next() {
const done = i === LIMIT;
const value = done ? undefined : i++;
return Promise.resolve({ value, done });
},
return() {
// This will be reached if the consumer called 'break' or 'return' early in the loop.
return { done: true };
},
};
},
};
(async () => {
for await (const num of asyncIterable) {
console.log(num);
}
})();
// 0
// 1
// 2
Iteration über asynchrone Generatoren
Da die Rückgabewerte von asynchronen Generatorfunktionen dem asynchronen Iterierbaren-Protokoll entsprechen, können sie mit for await...of durchlaufen werden.
async function* asyncGenerator() {
let i = 0;
while (i < 3) {
yield i++;
}
}
(async () => {
for await (const num of asyncGenerator()) {
console.log(num);
}
})();
// 0
// 1
// 2
Für ein konkreteres Beispiel der Iteration über einen asynchronen Generator mit for await...of, betrachten Sie die Iteration über Daten einer API.
Dieses Beispiel erstellt zuerst ein asynchrones Iterable für einen Datenstrom und verwendet es dann, um die GröÃe der Antwort von der API zu bestimmen.
async function* streamAsyncIterable(stream) {
const reader = stream.getReader();
try {
while (true) {
const { done, value } = await reader.read();
if (done) return;
yield value;
}
} finally {
reader.releaseLock();
}
}
// Fetches data from URL and calculates response size using the async generator.
async function getResponseSize(url) {
const response = await fetch(url);
// Will hold the size of the response, in bytes.
let responseSize = 0;
// The for-await-of loop. Async iterates over each portion of the response.
for await (const chunk of streamAsyncIterable(response.body)) {
// Incrementing the total response length.
responseSize += chunk.length;
}
console.log(`Response Size: ${responseSize} bytes`); // "Response Size: 1071472"
return responseSize;
}
getResponseSize("https://jsonplaceholder.typicode.com/photos");
Iteration über synchrone Iterables und Generatoren
for await...of-Schleife verbraucht auch synchrone Iterables und Generatoren. In diesem Fall wartet sie intern auf die ausgegebenen Werte, bevor sie der Schleifensteuerungsvariable zugewiesen werden.
function* generator() {
yield 0;
yield 1;
yield Promise.resolve(2);
yield Promise.resolve(3);
yield 4;
}
(async () => {
for await (const num of generator()) {
console.log(num);
}
})();
// 0
// 1
// 2
// 3
// 4
// compare with for-of loop:
for (const numOrPromise of generator()) {
console.log(numOrPromise);
}
// 0
// 1
// Promise { 2 }
// Promise { 3 }
// 4
Wenn ein synchroner Generator ein abgelehntes Promise liefert, ruft for await...of die return()-Methode des Generators auf, bevor der Ablehnungsgrund ausgelöst wird, was es den finally-Blöcken innerhalb dieses Generators ermöglicht, zu laufen.
function* generatorWithRejectedPromises() {
try {
yield 0;
yield 1;
yield Promise.resolve(2);
yield Promise.reject(new Error("failed"));
yield 4;
throw new Error("throws");
} finally {
console.log("called finally");
}
}
(async () => {
try {
for await (const num of generatorWithRejectedPromises()) {
console.log(num);
}
} catch (e) {
console.log("caught", e);
}
})();
// 0
// 1
// 2
// called finally
// caught Error: failed
Spezifikationen
| Spezifikation |
|---|
| ECMAScript® 2027 Language Specification > # sec-for-in-and-for-of-statements > |