Generatorfuncties in JavaScript

Generatorfuncties in JavaScript

In dit artikel leggen we generatorfuncties in JavaScript uit.

YouTube Video

Generatorfuncties in JavaScript

JavaScript-generatorfuncties zijn speciale functies die verschillen van gewone functies doordat ze lui uitgevoerd kunnen worden en kunnen pauzeren en hervatten. Door generatorfuncties te begrijpen, kun je asynchrone operaties en sequentiële verwerking van grote data efficiënt afhandelen. Hier geven we een gedetailleerde uitleg over hoe generatorfuncties werken, hoe je ze gebruikt en praktische toepassingen.

Wat zijn generatorfuncties?

Een generatorfunctie wordt gedefinieerd met function* (een functiedefinitie met een sterretje) en kan, in tegenstelling tot gewone functies, de uitvoering halverwege pauzeren en hervatten terwijl de status behouden blijft. Generatorfuncties maken "luie uitvoering" mogelijk en leveren resultaten stapsgewijs, waardoor efficiënt geheugengebruik en sequentiële verwerking mogelijk is.

Syntax

1function* generatorFunction() {
2    yield 'First value';
3    yield 'Second value';
4    return 'Done';
5}

Op deze manier kan een generatorfunctie meerdere yield-expressies hebben en yield gebruiken om de uitvoering te pauzeren. Wanneer een generatorfunctie wordt aangeroepen, wordt de body van de functie niet direct uitgevoerd en wordt een generatorobject geretourneerd. Je kunt de methode next() aanroepen op dit object om de functie te hervatten vanaf het punt waar deze was gepauzeerd.

Basisgebruik van generatorfuncties

Laten we vervolgens een eenvoudig voorbeeld bekijken van het gebruik van generatorfuncties.

 1function* simpleGenerator() {
 2    yield 1;
 3    yield 2;
 4    yield 3;
 5}
 6
 7const gen = simpleGenerator();
 8
 9console.log(gen.next()); // { value: 1, done: false }
10console.log(gen.next()); // { value: 2, done: false }
11console.log(gen.next()); // { value: 3, done: false }
12console.log(gen.next()); // { value: undefined, done: true }

Een belangrijk punt om hier op te merken is dat de generator elke keer waarden retourneert met yield, en zolang de done-eigenschap false is, betekent dit dat er meer waarden komen. De laatste aanroep van next() retourneert done: true, wat aangeeft dat de generator is voltooid.

De for...of-syntaxis gebruiken

Met for...of kun je eenvoudig elke yield-waarde uit een generator ophalen.

 1function* simpleGenerator() {
 2    yield 1;
 3    yield 2;
 4    yield 3;
 5}
 6
 7const gen = simpleGenerator();
 8
 9for (const value of gen) {
10    console.log(value); // 1, 2, 3
11}
  • for...of roept automatisch .next() aan op itereerbare objecten, waaronder generators, en blijft herhalen totdat done true wordt.
  • Binnen de lus wordt value achtereenvolgens elke yield-waarde toegewezen.
  • Het gebruik van for...of is heel eenvoudig omdat je .next() niet handmatig hoeft aan te roepen.

Het sleutelwoord yield en waarden pauzeren

yield is een sleutelwoord dat een pauzepunt binnen een generatorfunctie aangeeft. De waarde rechts van yield wordt geretourneerd wanneer next() wordt aangeroepen. Bovendien maakt yield tweerichtingscommunicatie mogelijk. Met andere woorden, wanneer een waarde wordt doorgegeven als argument aan de next()-methode, wordt die waarde naar de generatorfunctie gestuurd.

 1function* generatorWithYield() {
 2    const value1 = yield 'First yield';
 3    console.log('Received value:', value1);
 4    const value2 = yield 'Second yield';
 5    console.log('Received value:', value2);
 6}
 7
 8const gen = generatorWithYield();
 9
10console.log(gen.next());        // { value: 'First yield', done: false }
11console.log(gen.next('Apple')); // Received value: Apple
12                                // { value: 'Second yield', done: false }
13console.log(gen.next('Banana'));// Received value: Banana
14                                // { value: undefined, done: true }

In dit voorbeeld stuurt de aanroep next('Apple') de waarde 'Apple' naar de generatorfunctie, waar deze binnen de functie wordt gebruikt.

Het beheren van de generatorstatus

Generatoren kunnen hun uitvoeringsstatus behouden, wat zorgt voor een beknopte weergave van lange lussen of sequentiële verwerking. Het volgende voorbeeld toont een generator die onbeperkt nummers genereert.

 1function* infiniteGenerator() {
 2    let i = 0;
 3    while (true) {
 4        yield i++;
 5        if (i > 10) {
 6            break;
 7        }
 8    }
 9}
10
11const gen = infiniteGenerator();
12
13for (const value of gen) {
14    if (value === 3) break;
15    console.log(value); // 0, 1, 2
16}

Deze generator produceert continu nummers met behulp van een while(true)-lus, zodat je waarden naar behoefte kunt verkrijgen. Dit maakt efficiënte verwerking van grote datasets mogelijk.

Toepassingen van Generatorfuncties

Generatorfuncties zijn geschikt voor het achtereenvolgens uitvoeren van meerdere processen. Bijvoorbeeld, ze zijn nuttig voor het achtereenvolgens verwerken van API-aanvragen of het verdelen en verwerken van grote bestanden.

1function* apiRequestGenerator() {
2    yield fetch('https://codesparklab.com/json/example1.json');
3    yield fetch('https://codesparklab.com/json/example2.json');
4    yield fetch('https://codesparklab.com/json/example3.json');
5}

Zo zijn generators, die kunnen worden gebruikt voor asynchrone verwerking, enorm handig voor efficiënte sequentiële gegevensverwerking.

Asynchrone Generators

Asynchrone generators geïntroduceerd in ES2018 stellen je in staat om asynchrone waarden opeenvolgend te retourneren door async en yield te combineren. Dit maakt het mogelijk om asynchrone verwerking beknopt te schrijven in combinatie met await.

Syntax

 1async function* asyncGenerator() {
 2    yield await Promise.resolve(1);
 3    yield await Promise.resolve(2);
 4    yield await Promise.resolve(3);
 5}
 6
 7const gen = asyncGenerator();
 8
 9(async () => {
10    for await (const value of gen) {
11        console.log(value); // 1, 2, 3
12    }
13})();

Asynchrone generators kunnen waarden opeenvolgend ophalen met behulp van een for await...of-lus. Dit patroon is vooral nuttig bij het verwerken van asynchrone datastromen.

Praktisch Voorbeeld: Het Vereenvoudigen van Asynchrone Verwerking met Generators

Generatorfuncties worden ook gebruikt om de flow van asynchrone verwerking te vereenvoudigen. Bijvoorbeeld, door yield en Promise te combineren zoals hieronder weergegeven, kun je asynchrone bewerkingen schrijven die synchroon lijken.

 1function* asyncFlow() {
 2    const data1 = yield fetch('https://codesparklab.com/json/example1.json');
 3    console.log(data1);
 4    const data2 = yield fetch('https://codesparklab.com/json/example2.json');
 5    console.log(data2);
 6}
 7
 8const gen = asyncFlow();
 9
10function handleAsync(generator) {
11    const next = (promise) => {
12        promise.then((result) => {
13        const { value, done } = generator.next(result);
14        if (!done) {
15            next(value);
16        }
17        });
18    };
19
20    next(generator.next().value);
21}
22
23handleAsync(gen);

Deze code voert achtereenvolgens API-aanvragen uit met behulp van een generator en verwerkt de resultaten.

Samenvatting

Generatorfuncties behoren tot de krachtige functies van JavaScript, omdat ze het mogelijk maken de uitvoering van een functie te pauzeren en te hervatten. Dit maakt sequentiële verwerking, asynchrone verwerking en efficiënte manipulatie van grote datasets mogelijk. Het begrijpen van generators is een belangrijke stap in het beheersen van geavanceerde technieken in JavaScript.

Je kunt het bovenstaande artikel volgen met Visual Studio Code op ons YouTube-kanaal. Bekijk ook het YouTube-kanaal.

YouTube Video