Ontdek JavaScript Async Iterator Helpers om stroomverwerking te revolutioneren. Leer hoe u asynchrone datastromen efficiënt beheert met map, filter, take, drop en meer.
JavaScript Async Iterator Helpers: Krachtige Stroomverwerking voor Moderne Applicaties
In de moderne JavaScript-ontwikkeling is het omgaan met asynchrone datastromen een veelvoorkomende vereiste. Of u nu gegevens ophaalt van een API, grote bestanden verwerkt of real-time evenementen afhandelt, het efficiënt beheren van asynchrone data is cruciaal. JavaScript's Async Iterator Helpers bieden een krachtige en elegante manier om deze stromen te verwerken, met een functionele en samenstelbare benadering van datamanipulatie.
Wat zijn Async Iterators en Async Iterables?
Voordat we dieper ingaan op Async Iterator Helpers, is het belangrijk de onderliggende concepten te begrijpen: Async Iterators en Async Iterables.
Een Async Iterable is een object dat een manier definieert om asynchroon over zijn waarden te itereren. Dit doet het door de @@asyncIterator
-methode te implementeren, die een Async Iterator retourneert.
Een Async Iterator is een object dat een next()
-methode biedt. Deze methode retourneert een promise die resulteert in een object met twee eigenschappen:
value
: De volgende waarde in de reeks.done
: Een boolean die aangeeft of de reeks volledig is doorlopen.
Hier is een eenvoudig voorbeeld:
asynchrone functie* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 500)); // Simuleer een asynchrone operatie
yield i;
}
}
const asyncIterable = generateSequence(5);
(async () => {
for await (const value of asyncIterable) {
console.log(value); // Output: 1, 2, 3, 4, 5 (met 500ms vertraging tussen elke)
}
})();
In dit voorbeeld is generateSequence
een async generator-functie die asynchroon een reeks getallen produceert. De for await...of
-lus wordt gebruikt om de waarden uit de async iterable te consumeren.
Introductie van Async Iterator Helpers
Async Iterator Helpers breiden de functionaliteit van Async Iterators uit met een set methoden voor het transformeren, filteren en manipuleren van asynchrone datastromen. Ze maken een functionele en samenstelbare programmeerstijl mogelijk, wat het eenvoudiger maakt om complexe dataverwerkingspipelines te bouwen.
De belangrijkste Async Iterator Helpers zijn:
map()
: Transformeert elk element van de stroom.filter()
: Selecteert elementen uit de stroom op basis van een voorwaarde.take()
: Geeft de eerste N elementen van de stroom terug.drop()
: Slaat de eerste N elementen van de stroom over.toArray()
: Verzamelt alle elementen van de stroom in een array.forEach()
: Voert een opgegeven functie eenmaal uit voor elk element in de stroom.some()
: Controleert of ten minste één element aan een opgegeven voorwaarde voldoet.every()
: Controleert of alle elementen aan een opgegeven voorwaarde voldoen.find()
: Geeft het eerste element terug dat aan een opgegeven voorwaarde voldoet.reduce()
: Past een functie toe op een accumulator en elk element om dit te reduceren tot één enkele waarde.
Laten we elke helper met voorbeelden bekijken.
map()
De map()
-helper transformeert elk element van de async iterable met behulp van een opgegeven functie. Het retourneert een nieuwe async iterable met de getransformeerde waarden.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(5);
const doubledIterable = asyncIterable.map(x => x * 2);
(async () => {
for await (const value of doubledIterable) {
console.log(value); // Output: 2, 4, 6, 8, 10 (met 100ms vertraging)
}
})();
In dit voorbeeld verdubbelt map(x => x * 2)
elk getal in de reeks.
filter()
De filter()
-helper selecteert elementen uit de async iterable op basis van een opgegeven voorwaarde (predicaatfunctie). Het retourneert een nieuwe async iterable die alleen de elementen bevat die aan de voorwaarde voldoen.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(10);
const evenNumbersIterable = asyncIterable.filter(x => x % 2 === 0);
(async () => {
for await (const value of evenNumbersIterable) {
console.log(value); // Output: 2, 4, 6, 8, 10 (met 100ms vertraging)
}
})();
In dit voorbeeld selecteert filter(x => x % 2 === 0)
alleen de even getallen uit de reeks.
take()
De take()
-helper geeft de eerste N elementen van de async iterable terug. Het retourneert een nieuwe async iterable die alleen het opgegeven aantal elementen bevat.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(5);
const firstThreeIterable = asyncIterable.take(3);
(async () => {
for await (const value of firstThreeIterable) {
console.log(value); // Output: 1, 2, 3 (met 100ms vertraging)
}
})();
In dit voorbeeld selecteert take(3)
de eerste drie getallen uit de reeks.
drop()
De drop()
-helper slaat de eerste N elementen van de async iterable over en geeft de rest terug. Het retourneert een nieuwe async iterable die de resterende elementen bevat.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(5);
const afterFirstTwoIterable = asyncIterable.drop(2);
(async () => {
for await (const value of afterFirstTwoIterable) {
console.log(value); // Output: 3, 4, 5 (met 100ms vertraging)
}
})();
In dit voorbeeld slaat drop(2)
de eerste twee getallen uit de reeks over.
toArray()
De toArray()
-helper consumeert de volledige async iterable en verzamelt alle elementen in een array. Het retourneert een promise die resulteert in een array die alle elementen bevat.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(5);
(async () => {
const numbersArray = await asyncIterable.toArray();
console.log(numbersArray); // Output: [1, 2, 3, 4, 5]
})();
In dit voorbeeld verzamelt toArray()
alle getallen uit de reeks in een array.
forEach()
De forEach()
-helper voert een opgegeven functie eenmaal uit voor elk element in de async iterable. Het retourneert *geen* nieuwe async iterable, maar voert de functie uit voor het neveneffect. Dit kan handig zijn voor operaties zoals loggen of het bijwerken van een UI.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(3);
(async () => {
await asyncIterable.forEach(value => {
console.log("Value:", value);
});
console.log("forEach completed");
})();
// Output: Value: 1, Value: 2, Value: 3, forEach completed
some()
De some()
-helper test of ten minste één element in de async iterable slaagt voor de test die door de opgegeven functie wordt geïmplementeerd. Het retourneert een promise die resulteert in een booleaanse waarde (true
als ten minste één element aan de voorwaarde voldoet, anders false
).
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(5);
(async () => {
const hasEvenNumber = await asyncIterable.some(x => x % 2 === 0);
console.log("Has even number:", hasEvenNumber); // Output: Has even number: true
})();
every()
De every()
-helper test of alle elementen in de async iterable slagen voor de test die door de opgegeven functie wordt geïmplementeerd. Het retourneert een promise die resulteert in een booleaanse waarde (true
als alle elementen aan de voorwaarde voldoen, anders false
).
async function* generateSequence(end) {
for (let i = 2; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(4);
(async () => {
const areAllEven = await asyncIterable.every(x => x % 2 === 0);
console.log("Are all even:", areAllEven); // Output: Are all even: true
})();
find()
De find()
-helper geeft het eerste element in de async iterable terug dat aan de opgegeven testfunctie voldoet. Als geen enkele waarde aan de testfunctie voldoet, wordt undefined
geretourneerd. Het retourneert een promise die resulteert in het gevonden element of undefined
.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(5);
(async () => {
const firstEven = await asyncIterable.find(x => x % 2 === 0);
console.log("First even number:", firstEven); // Output: First even number: 2
})();
reduce()
De reduce()
-helper voert een door de gebruiker geleverde "reducer"-callbackfunctie uit op elk element van de async iterable, in volgorde, waarbij de retourwaarde van de berekening op het voorgaande element wordt doorgegeven. Het eindresultaat van het uitvoeren van de reducer over alle elementen is één enkele waarde. Het retourneert een promise die resulteert in de uiteindelijke geaccumuleerde waarde.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(5);
(async () => {
const sum = await asyncIterable.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
console.log("Sum:", sum); // Output: Sum: 15
})();
Praktische Voorbeelden en Toepassingen
Async Iterator Helpers zijn waardevol in diverse scenario's. Laten we enkele praktische voorbeelden bekijken:
1. Data Verwerken van een Streaming API
Stel u voor dat u een real-time datavisualisatie-dashboard bouwt dat gegevens ontvangt van een streaming API. De API stuurt continu updates, en u moet deze updates verwerken om de laatste informatie weer te geven.
async function* fetchDataFromAPI(url) {
let response = await fetch(url);
if (!response.body) {
throw new Error("ReadableStream not supported in this environment");
}
const reader = response.body.getReader();
const decoder = new TextDecoder();
try {
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
const chunk = decoder.decode(value);
// Ervan uitgaande dat de API JSON-objecten stuurt, gescheiden door nieuwe regels
const lines = chunk.split('\n');
for (const line of lines) {
if (line.trim() !== '') {
yield JSON.parse(line);
}
}
}
} finally {
reader.releaseLock();
}
}
const apiURL = 'https://example.com/streaming-api'; // Vervang door uw API URL
const dataStream = fetchDataFromAPI(apiURL);
// Verwerk de datastroom
(async () => {
for await (const data of dataStream.filter(item => item.type === 'metric').map(item => ({ timestamp: item.timestamp, value: item.value }))) {
console.log('Processed Data:', data);
// Werk het dashboard bij met de verwerkte gegevens
}
})();
In dit voorbeeld haalt fetchDataFromAPI
gegevens op van een streaming API, parseert de JSON-objecten en levert ze op als een async iterable. De filter
-helper selecteert alleen de metrieken, en de map
-helper transformeert de gegevens naar het gewenste formaat voordat het dashboard wordt bijgewerkt.
2. Grote Bestanden Lezen en Verwerken
Stel dat u een groot CSV-bestand met klantgegevens moet verwerken. In plaats van het hele bestand in het geheugen te laden, kunt u Async Iterator Helpers gebruiken om het stuk voor stuk te verwerken.
async function* readLinesFromFile(filePath) {
const file = await fsPromises.open(filePath, 'r');
try {
let buffer = Buffer.alloc(1024);
let fileOffset = 0;
let remainder = '';
while (true) {
const { bytesRead } = await file.read(buffer, 0, buffer.length, fileOffset);
if (bytesRead === 0) {
if (remainder) {
yield remainder;
}
break;
}
fileOffset += bytesRead;
const chunk = buffer.toString('utf8', 0, bytesRead);
const lines = chunk.split('\n');
lines[0] = remainder + lines[0];
remainder = lines.pop() || '';
for (const line of lines) {
yield line;
}
}
} finally {
await file.close();
}
}
const filePath = './customer_data.csv'; // Vervang door uw bestandspad
const lines = readLinesFromFile(filePath);
// Verwerk de regels
(async () => {
for await (const customerData of lines.drop(1).map(line => line.split(',')).filter(data => data[2] === 'USA')) {
console.log('Customer from USA:', customerData);
// Verwerk klantgegevens uit de VS
}
})();
In dit voorbeeld leest readLinesFromFile
het bestand regel voor regel en levert elke regel op als een async iterable. De drop(1)
-helper slaat de kopregel over, de map
-helper splitst de regel in kolommen, en de filter
-helper selecteert alleen klanten uit de VS.
3. Real-Time Evenementen Afhandelen
Async Iterator Helpers kunnen ook worden gebruikt om real-time evenementen van bronnen zoals WebSockets af te handelen. U kunt een async iterable maken die evenementen uitzendt zodra ze binnenkomen en vervolgens de helpers gebruiken om deze evenementen te verwerken.
async function* createWebSocketStream(url) {
const ws = new WebSocket(url);
yield new Promise((resolve, reject) => {
ws.onopen = () => {
resolve();
};
ws.onerror = (error) => {
reject(error);
};
});
try {
while (ws.readyState === WebSocket.OPEN) {
yield new Promise((resolve, reject) => {
ws.onmessage = (event) => {
resolve(JSON.parse(event.data));
};
ws.onerror = (error) => {
reject(error);
};
ws.onclose = () => {
resolve(null); // Resolve met null wanneer de verbinding sluit
}
});
}
} finally {
ws.close();
}
}
const websocketURL = 'wss://example.com/events'; // Vervang door uw WebSocket URL
const eventStream = createWebSocketStream(websocketURL);
// Verwerk de evenementenstroom
(async () => {
for await (const event of eventStream.filter(event => event.type === 'user_login').map(event => ({ userId: event.userId, timestamp: event.timestamp }))) {
console.log('User Login Event:', event);
// Verwerk gebruikerslogin-evenement
}
})();
In dit voorbeeld creëert createWebSocketStream
een async iterable die evenementen uitzendt die van een WebSocket worden ontvangen. De filter
-helper selecteert alleen gebruikerslogin-evenementen, en de map
-helper transformeert de gegevens naar het gewenste formaat.
Voordelen van het Gebruik van Async Iterator Helpers
- Verbeterde Leesbaarheid en Onderhoudbaarheid van Code: Async Iterator Helpers bevorderen een functionele en samenstelbare programmeerstijl, waardoor uw code gemakkelijker te lezen, te begrijpen en te onderhouden is. De ketenbare aard van de helpers stelt u in staat om complexe dataverwerkingspipelines op een beknopte en declaratieve manier uit te drukken.
- Efficiënt Geheugengebruik: Async Iterator Helpers verwerken datastromen 'lazy', wat betekent dat ze gegevens alleen verwerken wanneer dat nodig is. Dit kan het geheugengebruik aanzienlijk verminderen, vooral bij het omgaan met grote datasets of continue datastromen.
- Verbeterde Prestaties: Door gegevens in een stroom te verwerken, kunnen Async Iterator Helpers de prestaties verbeteren door te voorkomen dat de hele dataset in één keer in het geheugen hoeft te worden geladen. Dit kan met name voordelig zijn voor applicaties die grote bestanden, real-time data of streaming API's verwerken.
- Vereenvoudigd Asynchroon Programmeren: Async Iterator Helpers abstraheren de complexiteit van asynchroon programmeren, waardoor het eenvoudiger wordt om met asynchrone datastromen te werken. U hoeft promises of callbacks niet handmatig te beheren; de helpers handelen de asynchrone operaties achter de schermen af.
- Samenstelbare en Herbruikbare Code: Async Iterator Helpers zijn ontworpen om samenstelbaar te zijn, wat betekent dat u ze gemakkelijk aan elkaar kunt ketenen om complexe dataverwerkingspipelines te creëren. Dit bevordert hergebruik van code en vermindert duplicatie.
Browser- en Runtime-ondersteuning
Async Iterator Helpers zijn nog een relatief nieuwe functie in JavaScript. Eind 2024 bevinden ze zich in Fase 3 van het TC39-standaardisatieproces, wat betekent dat ze waarschijnlijk in de nabije toekomst gestandaardiseerd zullen worden. Ze worden echter nog niet standaard ondersteund in alle browsers en Node.js-versies.
Browserondersteuning: Moderne browsers zoals Chrome, Firefox, Safari en Edge voegen geleidelijk ondersteuning voor Async Iterator Helpers toe. U kunt de meest recente browsercompatibiliteitsinformatie controleren op websites zoals Can I use... om te zien welke browsers deze functie ondersteunen.
Node.js-ondersteuning: Recente versies van Node.js (v18 en hoger) bieden experimentele ondersteuning voor Async Iterator Helpers. Om ze te gebruiken, moet u mogelijk Node.js uitvoeren met de vlag --experimental-async-iterator
.
Polyfills: Als u Async Iterator Helpers moet gebruiken in omgevingen die ze niet standaard ondersteunen, kunt u een polyfill gebruiken. Een polyfill is een stukje code dat de ontbrekende functionaliteit biedt. Er zijn verschillende polyfill-bibliotheken beschikbaar voor Async Iterator Helpers; een populaire optie is de core-js
-bibliotheek.
Aangepaste Async Iterators Implementeren
Hoewel Async Iterator Helpers een handige manier bieden om bestaande async iterables te verwerken, moet u soms uw eigen aangepaste async iterators maken. Dit stelt u in staat om gegevens uit verschillende bronnen, zoals databases, API's of bestandssystemen, op een streaming manier te verwerken.
Om een aangepaste async iterator te maken, moet u de @@asyncIterator
-methode op een object implementeren. Deze methode moet een object retourneren met een next()
-methode. De next()
-methode moet een promise retourneren die resulteert in een object met de eigenschappen value
en done
.
Hier is een voorbeeld van een aangepaste async iterator die gegevens ophaalt van een gepagineerde API:
async function* fetchPaginatedData(baseURL) {
let page = 1;
let hasMore = true;
while (hasMore) {
const url = `${baseURL}?page=${page}`;
const response = await fetch(url);
const data = await response.json();
if (data.results.length === 0) {
hasMore = false;
break;
}
for (const item of data.results) {
yield item;
}
page++;
}
}
const apiBaseURL = 'https://api.example.com/data'; // Vervang door uw API URL
const paginatedData = fetchPaginatedData(apiBaseURL);
// Verwerk de gepagineerde gegevens
(async () => {
for await (const item of paginatedData) {
console.log('Item:', item);
// Verwerk het item
}
})();
In dit voorbeeld haalt fetchPaginatedData
gegevens op van een gepagineerde API en levert elk item op zodra het is opgehaald. De async iterator handelt de pagineringslogica af, waardoor het gemakkelijk is om de gegevens op een streaming manier te consumeren.
Mogelijke Uitdagingen en Overwegingen
Hoewel Async Iterator Helpers tal van voordelen bieden, is het belangrijk om u bewust te zijn van enkele mogelijke uitdagingen en overwegingen:
- Foutafhandeling: Correcte foutafhandeling is cruciaal bij het werken met asynchrone datastromen. U moet mogelijke fouten afhandelen die kunnen optreden tijdens het ophalen, verwerken of transformeren van gegevens. Het gebruik van
try...catch
-blokken en foutafhandelingstechnieken binnen uw async iterator helpers is essentieel. - Annulering: In sommige scenario's moet u mogelijk de verwerking van een async iterable annuleren voordat deze volledig is geconsumeerd. Dit kan handig zijn bij langlopende operaties of real-time datastromen waarbij u de verwerking wilt stoppen nadat aan een bepaalde voorwaarde is voldaan. Het implementeren van annuleringsmechanismen, zoals het gebruik van
AbortController
, kan u helpen asynchrone operaties effectief te beheren. - Tegendruk (Backpressure): Wanneer u te maken heeft met datastromen die sneller gegevens produceren dan ze kunnen worden geconsumeerd, wordt tegendruk een punt van zorg. Tegendruk verwijst naar het vermogen van de consument om de producent te signaleren om de snelheid waarmee gegevens worden uitgezonden te vertragen. Het implementeren van tegendrukmechanismen kan geheugenoverbelasting voorkomen en ervoor zorgen dat de datastroom efficiënt wordt verwerkt.
- Foutopsporing (Debugging): Het debuggen van asynchrone code kan uitdagender zijn dan het debuggen van synchrone code. Bij het werken met Async Iterator Helpers is het belangrijk om foutopsporingstools en -technieken te gebruiken om de gegevensstroom door de pipeline te traceren en eventuele problemen te identificeren.
Best Practices voor het Gebruik van Async Iterator Helpers
Om het maximale uit Async Iterator Helpers te halen, overweeg de volgende best practices:
- Gebruik Beschrijvende Variabelennamen: Kies beschrijvende variabelennamen die duidelijk het doel van elke async iterable en helper aangeven. Dit maakt uw code gemakkelijker te lezen en te begrijpen.
- Houd Helperfuncties Beknopt: Houd de functies die aan Async Iterator Helpers worden doorgegeven zo beknopt en gefocust mogelijk. Vermijd het uitvoeren van complexe operaties binnen deze functies; maak in plaats daarvan afzonderlijke functies voor complexe logica.
- Keten Helpers voor Leesbaarheid: Keten Async Iterator Helpers aan elkaar om een duidelijke en declaratieve dataverwerkingspipeline te creëren. Vermijd het overmatig nesten van helpers, omdat dit uw code moeilijker leesbaar kan maken.
- Handel Fouten Netjes af: Implementeer de juiste foutafhandelingsmechanismen om mogelijke fouten die tijdens de dataverwerking kunnen optreden op te vangen en af te handelen. Geef informatieve foutmeldingen om problemen te helpen diagnosticeren en op te lossen.
- Test Uw Code Grondig: Test uw code grondig om ervoor te zorgen dat deze verschillende scenario's correct afhandelt. Schrijf unit-tests om het gedrag van individuele helpers te verifiëren en integratietests om de algehele dataverwerkingspipeline te controleren.
Geavanceerde Technieken
Aangepaste Helpers Samenstellen
U kunt uw eigen aangepaste async iterator helpers maken door bestaande helpers samen te stellen of nieuwe vanaf nul op te bouwen. Dit stelt u in staat de functionaliteit aan te passen aan uw specifieke behoeften en herbruikbare componenten te creëren.
async function* takeWhile(asyncIterable, predicate) {
for await (const value of asyncIterable) {
if (!predicate(value)) {
break;
}
yield value;
}
}
// Voorbeeldgebruik:
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(10);
const firstFive = takeWhile(asyncIterable, x => x <= 5);
(async () => {
for await (const value of firstFive) {
console.log(value);
}
})();
Meerdere Async Iterables Combineren
U kunt meerdere async iterables combineren tot één enkele async iterable met behulp van technieken zoals zip
of merge
. Dit stelt u in staat om gegevens uit meerdere bronnen tegelijk te verwerken.
async function* zip(asyncIterable1, asyncIterable2) {
const iterator1 = asyncIterable1[Symbol.asyncIterator]();
const iterator2 = asyncIterable2[Symbol.asyncIterator]();
while (true) {
const result1 = await iterator1.next();
const result2 = await iterator2.next();
if (result1.done || result2.done) {
break;
}
yield [result1.value, result2.value];
}
}
// Voorbeeldgebruik:
async function* generateSequence1(end) {
for (let i = 1; i <= end; i++) {
yield i;
}
}
async function* generateSequence2(end) {
for (let i = 10; i <= end + 9; i++) {
yield i;
}
}
const iterable1 = generateSequence1(5);
const iterable2 = generateSequence2(5);
(async () => {
for await (const [value1, value2] of zip(iterable1, iterable2)) {
console.log(value1, value2);
}
})();
Conclusie
JavaScript Async Iterator Helpers bieden een krachtige en elegante manier om asynchrone datastromen te verwerken. Ze bieden een functionele en samenstelbare benadering van datamanipulatie, wat het eenvoudiger maakt om complexe dataverwerkingspipelines te bouwen. Door de kernconcepten van Async Iterators en Async Iterables te begrijpen en de verschillende helper-methoden onder de knie te krijgen, kunt u de efficiëntie en onderhoudbaarheid van uw asynchrone JavaScript-code aanzienlijk verbeteren. Naarmate de ondersteuning in browsers en runtimes blijft groeien, staan Async Iterator Helpers op het punt een essentieel hulpmiddel te worden voor moderne JavaScript-ontwikkelaars.