Udbytte! Udbytte! Sådan fungerer generatorer i JavaScript.

Hvis titlen ikke allerede giver et tip, vil vi diskutere generatorer i dette stykke.

Før vi går ind i generatorer, lad os revidere nogle grundlæggende om funktioner.

  • I JavaScript er funktioner et sæt udsagn, der udfører en opgave og returnerer en værdi, der afslutter funktionen.
  • Hvis du kalder en funktion igen og igen, udfører den alle udsagnene igen og igen.
  • Pile, der er tilbage fra buen, kan ikke stoppes - de rammer kun eller misser. På samme måde kan en funktion, der først er kaldt, ikke stoppes, den kører, returnerer en værdi, kaster en fejl og stopper derefter efter at have udført alle udsagnene.

Vi behøver kun at huske disse 3 punkter for at forstå generatorer.

Generatorer

En generator er en speciel type funktion, som kan stoppe dens udførelse midtvejs og derefter starte fra samme punkt efter nogen tid. Generatorer er en kombination af funktioner og iteratorer. Dette er lidt af en forvirrende erklæring, men jeg vil sikre mig, at denne linje vil være klar i slutningen af ​​artiklen.

For klarhedens skyld skal du overveje at spille et spil og pludselig kræver mor noget arbejde. Du sætter spillet på pause, hjælper hende og genoptager derefter spillet igen. Det er det samme med generatorer.

En iterator er et objekt, der definerer en sekvens og potentielt en returværdi ved dens afslutning. - MDN.

Iteratorer i sig selv er et stort emne og er ikke formålet med denne artikel.

Grundlæggende syntaks

Generatorer defineres som en funktion med en stjerne (*) ved siden af ​​funktionen.

function* name(arguments) { statements}

name - Funktionsnavnet.

argumenter - Argumenter for funktionen.

udsagn - Funktionens krop.

Vend tilbage

En funktion kan returnere næsten alt lige fra en værdi, et objekt eller en anden funktion i sig selv. En generatorfunktion returnerer et specielt objekt kaldet generatorobjektet ( ikke helt sandt ). Objektet ligner uddraget nedenfor

false

Objektet har to egenskaber value og done. Værdien indeholder den værdi, der skal leveres . Udført består af en boolsk (true | false), der fortæller generatoren, om .next () vil give en værdi eller udefineret.

Ovenstående udsagn vil være vanskelige at fordøje. Lad os ændre det med et eksempel.

function* generator(e) { yield e + 10; yield e + 25; yield e + 33;}var generate = generator(27);
console.log(generate.next().value); // 37console.log(generate.next().value); // 52console.log(generate.next().value); // 60console.log(generate.next().value); // undefined

Lad os forstå mekanikken i ovenstående kode linje for linje.

linje 1–5: Linje 1–5 definerer generatoren med samme navn med et argument e. Inde i funktionens hoveddel indeholder den en masse udsagn med nøgleordets udbytte, og der foretages en vis operation efter det.

linje 6: Linje 6 tildeler generatoren til en variabel kaldet generere.

linjer 8–11: Disse linjer kalder en flok afconsole.loghver, der kalder generatoren kædet, til ennext metode, der krævervaluegeneratorens genstands egenskab.

Når en generatorfunktion kaldes, i modsætning til normale funktioner, starter den ikke udførelsen med det samme. I stedet returneres en iterator ( den faktiske årsag * bruges af en generator. Det fortæller JS, at et iteratorobjekt skal returneres ). Når next()metoden til iteratoren kaldes, starter og udføres udførelsen af ​​generatoren, indtil den finder den første yield sætning. På dette udbyttepunkt returneres generatorobjektet, hvis specifikationer allerede er forklaret. Hvis du ringer til next()funktionen igen, genoptages generatorfunktionen, indtil den finder en ny yield erklæring, og cyklussen vender tilbage, indtil alt yields er opbrugt.

Efter dette punkt, hvis next kaldes det, returnerer det generatorobjektet med udefineret værdi.

Lad os nu prøve at give en anden generatorfunktion fra den originale generator og også en returerklæring.

En returnerklæring i en generator får generatoren til at afslutte sin udførelse som enhver anden funktion. Den done property af generatoren objektet vil blive sat til true , og den value returnerede vil blive sat til den value ejendom af generatoren objekt. Alle andre yields vender tilbage undefined.

Hvis der kastes en fejl, stopper også udførelsen af ​​generatoren, hvilket giver en generator selv.

For yielding en generator er vi nødt til at specificere en * mod den yield for at fortælle JS, at der genereres en generator. De yield*delegerede til en anden generator funktion - det er grunden til, vi kan yield alle værdier af generator2 funktionen ved hjælp af generate.next()den oprindelige generator funktion. Den første værdi yieldeder fra den første generatorfunktion, og de sidste to yielded værdier genereres af generatorfunktionen, men yielded af den originale generator.

Fordele

Lazy loading

Lazy loading er i det væsentlige kun værdiansættelse, når der er behov for det. Som vi vil se i et kommende eksempel, kan vi faktisk gøre det med generatorer. Vi giver muligvis kun værdierne efter behov og ikke alle på samme tid.

Eksemplet nedenfor er fra et andet eksempel i denne artikel, og det genererer uendelige tilfældige tal. Her kan vi se, at vi kan kalde så mange, next()som vi vil, og ikke få alle de værdier, det producerer. Kun de nødvendige.

function * randomize() { while (true) {let random = Math.floor(Math.random()*1000); yield random; }}
var random= randomize();
console.log(random.next().value)

Hukommelseseffektiv

Som vi kan udlede fra ovenstående eksempel, er generatorer ekstremt hukommelseseffektive. Da vi kun ønsker værdierne efter behov, har vi brug for meget mindre lagerplads til lagring af disse værdier.

Faldgruber

Generatorer er ekstremt nyttige, men har også deres egne faldgruber.

  • Generatorer giver ikke tilfældig adgang som arrays og andre datastrukturer. Da værdierne vises en efter en ved opkald, kan vi ikke få adgang til tilfældige elementer.
  • Generatorer giver engangsadgang. Generatorer tillader dig ikke at gentage værdierne igen og igen. Når alle værdier er opbrugt, skal vi oprette en ny generatorinstans for at gentage alle værdier igen.

Hvorfor har vi brug for generatorer?

Generatorer leverer en bred vifte af anvendelser i JavaScript. Lad os prøve at genskabe nogle selv.

Implementering af Iteratorer

En iterator er et objekt, der gør det muligt for en programmør at krydse en container -Wikipedia

Vi udskriver alle de ord, der er til stede i en streng ved hjælp af iteratorer. Strenge er også iteratorer.

Iteratorer

const string = 'abcde';const iterator = string[Symbol.iterator]();console.log(iterator.next().value)console.log(iterator.next().value)console.log(iterator.next().value)console.log(iterator.next().value)console.log(iterator.next().value)

Her er det samme ved hjælp af generatorer

function * iterator() {yield 'a';yield 'b';yield 'c';yield 'd';yield 'e';}for (let x of iterator()) {console.log(x);}

Sammenligning af begge metoder er det let at se, at vi ved hjælp af generatorer kan gøre det med mindre rod. Jeg ved, at det ikke er et meget godt eksempel, men nok til at bevise følgende punkter:

  • Ingen implementering af next()
  • No [Symbol.iterator]() invocation
  • In some cases, we even need to set the object.done property return value to true/false using iterators.

Async-Await ~ Promises+Generators

You can read my previous article about Async/Await if you want to learn about them, and check out this for Promises.

Crudely, Async/Await is just an implementation of Generators used with Promises.

Async-Await

async function async-await(){let a=await(task1);console.log(a);
let b=await(task2);console.log(b);
let c=await(task3);console.log(c);
}

Promises+Generators

function * generator-promise(){let a=yield Promise1();console.log(a);let b=yield Promise1();console.log(b);let c=yield Promise1();console.log(c);
}

As we can see, both produce the same result and almost in a similar fashion too. It’s because the Async/Await mechanism is loosely based on a combination of generators and promise. There is a lot more to Async/Await than shown above, but just for showing the use of a generator, we can consider this.

Infinite Data Structure

Overskriften kan være lidt vildledende, men det er sandt. Vi kan oprette generatorer ved hjælp af en while-loop, der aldrig ender og altid giver en værdi.

function * randomize() { while (true) {let random = Math.floor(Math.random()*1000); yield random; }}var random= randomize();while(true)console.log(random.next().value)

I ovenstående uddrag opretter vi en uendelig generator, som giver et tilfældigt tal ved hver next() påkaldelse. Det kan kaldes som en uendelig strøm af tilfældige tal. Dette er et meget grundlæggende eksempel.

Konklusion

Der er endnu meget at dække om generatorer, og dette var kun en introduktion til emnet. Håber du har lært noget nyt, og artiklen var let at forstå.

Følg mig og bifal!