Signatur
Beschreibung
Symbol.asyncIterator ist eine statische Dateneigenschaft von Symbol. Sie enthält eines der wohlbekannten Symbole (englisch „well-known symbols“). Hat ein Objekt eine Methode unter diesem Schlüssel, gilt es als asynchron iterierbar. Die Methode muss ein Objekt zurückgeben, das das Async-Iterator-Protokoll erfüllt. Dessen next()-Methode liefert also ein Promise, das zu { value, done } aufgelöst wird.
Die Schleife for await...of und yield* in asynchronen Generatoren rufen diese Methode automatisch auf. Array.fromAsync() tut das ebenfalls. Das Symbol ist nützlich, wenn Daten nach und nach eintreffen: zum Beispiel bei seitenweise abgerufenen API-Ergebnissen, Datenströmen (Streams), WebSocket-Nachrichten oder Zeilen aus Dateien.
Am einfachsten implementierst du die Methode als asynchronen Generator (async *[Symbol.asyncIterator]() { … }). Der Generator erzeugt automatisch ein Objekt, das dem Protokoll entspricht. Eingebaut haben das Symbol zum Beispiel ReadableStream (in neueren Browsern und in Node.js) sowie Node.js-Readable-Streams und events.on().
Die Eigenschaft selbst ist nicht beschreibbar (writable: false), nicht aufzählbar (enumerable: false) und nicht konfigurierbar (configurable: false).
Rückgabewert
Symbol.asyncIterator. Es ist in allen Realms (z. B. iframes) identisch.Beispiele
Eigenes asynchron iterierbares Objekt mit async-Generator
const countdown = {
from: 3,
async *[Symbol.asyncIterator]() {
for (let i = this.from; i > 0; i--) {
// Verzögerung simulieren
await new Promise((r) => setTimeout(r, 100));
yield i;
}
},
};
for await (const n of countdown) {
console.log(n);
}
Seitenweise API-Abfrage (Pagination) als asynchroner Iterator
class PagedResource {
constructor(url) {
this.url = url;
}
async *[Symbol.asyncIterator]() {
let next = this.url;
while (next) {
const res = await fetch(next);
const { items, nextPage } = await res.json();
yield* items; // einzelne Einträge weiterreichen
next = nextPage;
}
}
}
const users = new PagedResource('https://api.example.com/users?page=1');
for await (const user of users) {
console.log(user.name);
if (user.name === 'Stop') break; // break ruft return() auf und beendet den Generator
}
Protokoll manuell implementieren (ohne Generator)
const ticker = {
[Symbol.asyncIterator]() {
let count = 0;
return {
next: () =>
Promise.resolve(
count < 2 ? { value: `Tick ${++count}`, done: false } : { value: undefined, done: true }
),
return: () => {
console.log('Aufräumen');
return Promise.resolve({ value: undefined, done: true });
},
};
},
};
const result = await Array.fromAsync(ticker);
console.log(result);
console.log(typeof ticker[Symbol.asyncIterator]);
ReadableStream mit for await...of lesen
const response = await fetch('https://example.com/daten.txt');
const decoder = new TextDecoder();
for await (const chunk of response.body) {
console.log('Empfangen:', decoder.decode(chunk, { stream: true }).length, 'Zeichen');
}
// Wichtig · Fallstricke
- Nicht mit
Symbol.iteratorverwechseln: Normale Arrays haben keinSymbol.asyncIterator. Trotzdem funktioniertfor await...ofmit ihnen, weil die Schleife aufSymbol.iteratorzurückgreift und jeden Wert mitawaitauflöst. Umgekehrt klappt das nicht: Ein reines Async-Iterable lässt sich nicht mitfor...ofoder dem Spread-Operator (...) durchlaufen. for await...ofist nur inasync-Funktionen erlaubt oder auf oberster Ebene in ES-Modulen (Top-Level-await).- Bei manueller Implementierung muss
next()einPromisezurückgeben. Liefert es direkt ein{ value, done }-Objekt, funktioniert das zwar, weilawaitauch Nicht-Promises annimmt. Es widerspricht aber dem Protokoll. Biete außerdem einereturn()-Methode an, damit Ressourcen beibreakoder bei Fehlern freigegeben werden. - Die Elemente werden nacheinander verarbeitet, nicht parallel. Für echte Parallelität nutze
Promise.all(). - Kompatibilität: Das Symbol wird seit ES2018 in allen modernen Browsern und ab Node.js 10 unterstützt.
ReadableStreamist erst in neueren Browsern asynchron iterierbar (Safari erst spät). Prüfe die Unterstützung also gegebenenfalls mitSymbol.asyncIterator in stream.