PÔhjalik juhend JavaScripti generaatorite kohta, mis uurib nende funktsionaalsust, iteraatori protokolli rakendamist, kasutusjuhtumeid ja tÀiustatud tehnikaid.
JavaScripti generaatorid: iteraatori protokolli rakendamise meisterlikkus
JavaScripti generaatorid on vĂ”imas funktsioon, mis vĂ”eti kasutusele ECMAScript 6-s (ES6) ja mis oluliselt laiendab keele vĂ”imekust iteratiivsete protsesside ja asĂŒnkroonse programmeerimise kĂ€sitlemisel. Need pakuvad unikaalset viisi iteraatorite defineerimiseks, vĂ”imaldades loetavamat, hooldatavamat ja efektiivsemat koodi. See pĂ”hjalik juhend sĂŒveneb JavaScripti generaatorite maailma, uurides nende funktsionaalsust, iteraatori protokolli rakendamist, praktilisi kasutusjuhtumeid ja tĂ€iustatud tehnikaid.
Iteraatorite ja iteraatori protokolli mÔistmine
Enne generaatoritesse sĂŒvenemist on oluline mĂ”ista iteraatorite ja iteraatori protokolli kontseptsiooni. Iteraator on objekt, mis defineerib jada ja lĂ”petamisel potentsiaalselt ka tagastusvÀÀrtuse. TĂ€psemalt on iteraator iga objekt, millel on next()
meetod, mis tagastab objekti kahe omadusega:
value
: JÀrgmine vÀÀrtus jadas.done
: Kahendmuutuja, mis nÀitab, kas iteraator on lÔpule jÔudnud.true
tÀhistab jada lÔppu.
Iteraatori protokoll on lihtsalt standardne viis, kuidas objekt saab ennast itereeritavaks muuta. Objekt on itereeritav, kui see defineerib oma iteratsioonikĂ€itumise, nĂ€iteks milliseid vÀÀrtusi tsĂŒklitakse lĂ€bi for...of
konstruktsioonis. Itereeritav olemiseks peab objekt implementeerima @@iterator
meetodi, millele pÀÀseb ligi Symbol.iterator
kaudu. See meetod peab tagastama iteraatori objekti.
Paljud sisseehitatud JavaScripti andmestruktuurid, nagu massiivid, sÔned, map'id ja set'id, on olemuslikult itereeritavad, sest nad rakendavad iteraatori protokolli. See vÔimaldab meil nende elemente hÔlpsasti lÀbi kÀia, kasutades for...of
tsĂŒkleid.
NĂ€ide: massiivi itereerimine
const myArray = [1, 2, 3];
const iterator = myArray[Symbol.iterator]();
console.log(iterator.next()); // VĂ€ljund: { value: 1, done: false }
console.log(iterator.next()); // VĂ€ljund: { value: 2, done: false }
console.log(iterator.next()); // VĂ€ljund: { value: 3, done: false }
console.log(iterator.next()); // VĂ€ljund: { value: undefined, done: true }
for (const value of myArray) {
console.log(value); // VĂ€ljund: 1, 2, 3
}
JavaScripti generaatorite tutvustus
Generaator on eriline tĂŒĂŒpi funktsioon, mida saab peatada ja jĂ€tkata, vĂ”imaldades teil kontrollida andmete genereerimise voogu. Generaatorid defineeritakse kasutades function*
sĂŒntaksit ja yield
vÔtmesÔna.
function*
: See deklareerib generaatorfunktsiooni. Generaatorfunktsiooni kutsumine ei kĂ€ivita selle keha kohe; selle asemel tagastab see erilist tĂŒĂŒpi iteraatori, mida nimetatakse generaatori objektiks.yield
: See vÔtmesÔna peatab generaatori tÀitmise ja tagastab vÀÀrtuse kutsujale. Generaatori olek salvestatakse, mis vÔimaldab seda hiljem jÀtkata tÀpselt sealt, kus see peatati.
Generaatorfunktsioonid pakuvad lĂŒhikest ja elegantset viisi iteraatori protokolli rakendamiseks. Nad loovad automaatselt iteraatori objekte, mis tegelevad oleku haldamise ja vÀÀrtuste andmise keerukustega.
NĂ€ide: lihtne generaator
function* numberGenerator() {
yield 1;
yield 2;
yield 3;
}
const gen = numberGenerator();
console.log(gen.next()); // VĂ€ljund: { value: 1, done: false }
console.log(gen.next()); // VĂ€ljund: { value: 2, done: false }
console.log(gen.next()); // VĂ€ljund: { value: 3, done: false }
console.log(gen.next()); // VĂ€ljund: { value: undefined, done: true }
Kuidas generaatorid rakendavad iteraatori protokolli
Generaatorfunktsioonid rakendavad iteraatori protokolli automaatselt. Kui defineerite generaatorfunktsiooni, loob JavaScript automaatselt generaatori objekti, millel on next()
meetod. Iga kord, kui kutsute generaatori objektil next()
meetodit, tÀidetakse generaatorfunktsiooni kuni yield
vÔtmesÔnani jÔudmiseni. VÀÀrtus, mis on seotud yield
vÔtmesÔnaga, tagastatakse next()
poolt tagastatud objekti value
omadusena ja done
omadus seatakse vÀÀrtusele false
. Kui generaatorfunktsioon lÔpetab (kas jÔudes funktsiooni lÔppu vÔi kohates return
lauset), muutub done
omadus true
-ks ja value
omadus seatakse tagastatavale vÀÀrtusele (vÔi undefined
, kui selgesÔnalist return
lauset pole).
Oluline on mÀrkida, et generaatori objektid on ka ise itereeritavad! Neil on Symbol.iterator
meetod, mis lihtsalt tagastab generaatori objekti enda. See muudab generaatorite kasutamise for...of
tsĂŒklite ja muude itereeritavaid objekte ootavate konstruktsioonidega vĂ€ga lihtsaks.
JavaScripti generaatorite praktilised kasutusjuhud
Generaatorid on mitmekĂŒlgsed ja neid saab rakendada laias valikus stsenaariumides. Siin on mĂ”ned levinumad kasutusjuhud:
1. Kohandatud iteraatorid
Generaatorid lihtsustavad kohandatud iteraatorite loomist keerukate andmestruktuuride vÔi algoritmide jaoks. Selle asemel, et kÀsitsi implementeerida next()
meetodit ja hallata olekut, saate kasutada yield
-i vÀÀrtuste kontrollitud viisil tootmiseks.
NĂ€ide: kahendpuu itereerimine
class Node {
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
}
}
class BinaryTree {
constructor(root) {
this.root = root;
}
*[Symbol.iterator]() {
function* inOrderTraversal(node) {
if (node) {
yield* inOrderTraversal(node.left); // rekursiivselt anna vÀÀrtused vasakpoolsest alampuust
yield node.value;
yield* inOrderTraversal(node.right); // rekursiivselt anna vÀÀrtused parempoolsest alampuust
}
}
yield* inOrderTraversal(this.root);
}
}
// Loo nÀidis kahendpuu
const root = new Node(1);
root.left = new Node(2);
root.right = new Node(3);
root.left.left = new Node(4);
root.left.right = new Node(5);
const tree = new BinaryTree(root);
// Itereeri ĂŒle puu, kasutades kohandatud iteraatorit
for (const value of tree) {
console.log(value); // VĂ€ljund: 4, 2, 5, 1, 3
}
See nÀide demonstreerib, kuidas generaatorfunktsioon inOrderTraversal
rekursiivselt lÀbib kahendpuud ja annab vÀÀrtused in-order jÀrjestuses. yield*
sĂŒntaksit kasutatakse iteratsiooni delegeerimiseks teisele itereeritavale (antud juhul rekursiivsetele kutsetele inOrderTraversal
-ile), lamedades efektiivselt pesastatud itereeritava.
2. LÔpmatud jadad
Generaatoreid saab kasutada lĂ”pmatute vÀÀrtuste jadade loomiseks, nagu Fibonacci numbrid vĂ”i algarvud. Kuna generaatorid toodavad vÀÀrtusi nĂ”udmisel, ei tarbi nad mĂ€lu enne, kui vÀÀrtust tegelikult kĂŒsitakse.
NĂ€ide: Fibonacci numbrite genereerimine
function* fibonacciGenerator() {
let a = 0;
let b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
const fib = fibonacciGenerator();
console.log(fib.next().value); // VĂ€ljund: 0
console.log(fib.next().value); // VĂ€ljund: 1
console.log(fib.next().value); // VĂ€ljund: 1
console.log(fib.next().value); // VĂ€ljund: 2
console.log(fib.next().value); // VĂ€ljund: 3
// ... ja nii edasi
Funktsioon fibonacciGenerator
genereerib lĂ”pmatu jada Fibonacci numbreid. TsĂŒkkel while (true)
tagab, et generaator jÀtkab vÀÀrtuste tootmist lÔpmatuseni. Kuna vÀÀrtused genereeritakse nÔudmisel, saab see generaator esindada lÔpmatut jada ilma lÔpmatut mÀlu tarbimata.
3. AsĂŒnkroonne programmeerimine
Generaatoritel on oluline roll asĂŒnkroonses programmeerimises, eriti kui neid kombineerida promise'idega. Neid saab kasutada asĂŒnkroonse koodi kirjutamiseks, mis nĂ€eb vĂ€lja ja kĂ€itub nagu sĂŒnkroonne kood, muutes selle lugemise ja mĂ”istmise lihtsamaks.
NĂ€ide: asĂŒnkroonne andmete toomine generaatoritega
function fetchData(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then(response => response.json())
.then(data => resolve(data))
.catch(error => reject(error));
});
}
function* dataFetcher() {
try {
const user = yield fetchData('https://jsonplaceholder.typicode.com/users/1');
console.log('Kasutaja:', user);
const posts = yield fetchData(`https://jsonplaceholder.typicode.com/posts?userId=${user.id}`);
console.log('Postitused:', posts);
} catch (error) {
console.error('Viga andmete toomisel:', error);
}
}
function runGenerator(generator) {
const iterator = generator();
function iterate(result) {
if (result.done) return;
const promise = result.value;
promise
.then(value => iterate(iterator.next(value)))
.catch(error => iterator.throw(error));
}
iterate(iterator.next());
}
runGenerator(dataFetcher);
Selles nÀites toob generaatorfunktsioon dataFetcher
asĂŒnkroonselt kasutaja ja postituste andmeid, kasutades funktsiooni fetchData
, mis tagastab promise'i. VÔtmesÔna yield
peatab generaatori, kuni promise laheneb, vĂ”imaldades teil kirjutada asĂŒnkroonset koodi jĂ€rjestikuses, sĂŒnkroonse sarnases stiilis. Funktsioon runGenerator
on abifunktsioon, mis juhib generaatorit, kÀsitledes promise'ide lahendamist ja vigade levitamist.
Kuigi kaasaegses asĂŒnkroonses JavaScriptis eelistatakse sageli `async/await`-i, annab generaatorite varasema (ja mĂ”nikord siiani) kasutuse mĂ”istmine asĂŒnkroonse kontrollivoo jaoks vÀÀrtusliku sissevaate keele arengusse.
4. Andmevoog ja töötlemine
Generaatoreid saab kasutada suurte andmekogumite vĂ”i andmevoogude töötlemiseks mĂ€luefektiivsel viisil. AndmetĂŒkkide jĂ€rkjĂ€rgulise andmisega saate vĂ€ltida kogu andmestiku korraga mĂ€llu laadimist.
NÀide: suure CSV-faili töötlemine
const fs = require('fs');
const readline = require('readline');
async function* processCSV(filePath) {
const fileStream = fs.createReadStream(filePath);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
for await (const line of rl) {
// Töötle iga rida (nt parsi CSV andmed)
const data = line.split(',');
yield data;
}
}
async function main() {
const csvGenerator = processCSV('large_data.csv');
for await (const row of csvGenerator) {
console.log('Rida:', row);
// Teosta operatsioone igal real
}
}
main();
See nÀide kasutab fs
ja readline
mooduleid suure CSV-faili lugemiseks rida-realt. Generaatorfunktsioon processCSV
annab iga CSV-faili rea massiivina. async/await
sĂŒntaksit kasutatakse failiridade asĂŒnkroonseks itereerimiseks, tagades, et faili töödeldakse efektiivselt ilma peamist lĂ”ime blokeerimata. VĂ”ti on siin iga rea töötlemine *selle lugemise ajal*, mitte katse laadida kogu CSV esmalt mĂ€llu.
TĂ€iustatud generaatoritehnikad
1. Generaatorite kompositsioon `yield*`-ga
VÔtmesÔna yield*
vÔimaldab teil delegeerida iteratsiooni teisele itereeritavale objektile vÔi generaatorile. See on kasulik keerukate iteraatorite koostamiseks lihtsamatest.
NĂ€ide: mitme generaatori kombineerimine
function* generator1() {
yield 1;
yield 2;
}
function* generator2() {
yield 3;
yield 4;
}
function* combinedGenerator() {
yield* generator1();
yield* generator2();
yield 5;
}
const combined = combinedGenerator();
console.log(combined.next()); // VĂ€ljund: { value: 1, done: false }
console.log(combined.next()); // VĂ€ljund: { value: 2, done: false }
console.log(combined.next()); // VĂ€ljund: { value: 3, done: false }
console.log(combined.next()); // VĂ€ljund: { value: 4, done: false }
console.log(combined.next()); // VĂ€ljund: { value: 5, done: false }
console.log(combined.next()); // VĂ€ljund: { value: undefined, done: true }
Funktsioon combinedGenerator
kombineerib vÀÀrtused generaatoritest generator1
ja generator2
koos tÀiendava vÀÀrtusega 5. VÔtmesÔna yield*
lamedab efektiivselt pesastatud iteraatorid, tootes ĂŒheainsa vÀÀrtuste jada.
2. VÀÀrtuste saatmine generaatoritele `next()`-ga
Generaatori objekti next()
meetod vÔib aktsepteerida argumenti, mis seejÀrel edastatakse yield
-avalduse vÀÀrtusena generaatorfunktsioonis. See vÔimaldab kahesuunalist suhtlust generaatori ja kutsuja vahel.
NĂ€ide: interaktiivne generaator
function* interactiveGenerator() {
const input1 = yield 'Mis on sinu nimi?';
console.log('Saadud nimi:', input1);
const input2 = yield 'Mis on sinu lemmikvÀrv?';
console.log('Saadud vÀrv:', input2);
return `Tere, ${input1}! Sinu lemmikvÀrv on ${input2}.`;
}
const interactive = interactiveGenerator();
console.log(interactive.next().value); // VĂ€ljund: Mis on sinu nimi?
console.log(interactive.next('Alice').value); // VĂ€ljund: Saadud nimi: Alice
// VÀljund: Mis on sinu lemmikvÀrv?
console.log(interactive.next('Sinine').value); // VÀljund: Saadud vÀrv: Sinine
// VÀljund: Tere, Alice! Sinu lemmikvÀrv on Sinine.
console.log(interactive.next()); // VÀljund: { value: Tere, Alice! Sinu lemmikvÀrv on Sinine., done: true }
Selles nĂ€ites kĂŒsib funktsioon interactiveGenerator
kasutajalt nime ja lemmikvÀrvi. Meetodit next()
kasutatakse kasutaja sisendi tagasi saatmiseks generaatorile, mis seejÀrel kasutab seda isikupÀrastatud tervituse koostamiseks. See illustreerib, kuidas generaatoreid saab kasutada interaktiivsete programmide loomiseks, mis reageerivad vÀlisele sisendile.
3. Vigade kÀsitlemine `throw()`-ga
Generaatori objekti throw()
meetodit saab kasutada erandi viskamiseks generaatorfunktsiooni sees. See vÔimaldab vigade kÀsitlemist ja puhastamist generaatori kontekstis.
NÀide: vigade kÀsitlemine generaatoris
function* errorGenerator() {
try {
yield 'Alustan...';
throw new Error('Midagi lÀks valesti!');
yield 'Seda ei tÀideta.';
} catch (error) {
console.error('PĂŒĂŒtud viga:', error.message);
yield 'Taastun...';
}
yield 'LÔpetatud.';
}
const errorGen = errorGenerator();
console.log(errorGen.next().value); // VĂ€ljund: Alustan...
console.log(errorGen.next().value); // VĂ€ljund: PĂŒĂŒtud viga: Midagi lĂ€ks valesti!
// VĂ€ljund: Taastun...
console.log(errorGen.next().value); // VÀljund: LÔpetatud.
console.log(errorGen.next().value); // VĂ€ljund: undefined
Selles nÀites viskab funktsioon errorGenerator
vea try...catch
ploki sees. Plokk catch
kÀsitleb viga ja annab taasteteate. See demonstreerib, kuidas generaatoreid saab kasutada vigade sujuvaks kÀsitlemiseks ja tÀitmise jÀtkamiseks.
4. VÀÀrtuste tagastamine `return()`-ga
Generaatori objekti return()
meetodit saab kasutada generaatori enneaegseks lÔpetamiseks ja kindla vÀÀrtuse tagastamiseks. See vÔib olla kasulik ressursside puhastamiseks vÔi jada lÔpu signaalimiseks.
NÀide: generaatori varajane lÔpetamine
function* earlyExitGenerator() {
yield 1;
yield 2;
return 'Varajane vÀljumine!';
yield 3; // Seda ei tÀideta
}
const exitGen = earlyExitGenerator();
console.log(exitGen.next().value); // VĂ€ljund: 1
console.log(exitGen.next().value); // VĂ€ljund: 2
console.log(exitGen.next().value); // VÀljund: Varajane vÀljumine!
console.log(exitGen.next().value); // VĂ€ljund: undefined
console.log(exitGen.next().done); // VĂ€ljund: true
Selles nÀites lÔpetab funktsioon earlyExitGenerator
varakult, kui see kohtub return
lausega. Meetod return()
tagastab mÀÀratud vÀÀrtuse ja seab done
omaduse vÀÀrtuseks true
, mis nÀitab, et generaator on lÔpule jÔudnud.
JavaScripti generaatorite kasutamise eelised
- Parem koodi loetavus: Generaatorid vĂ”imaldavad teil kirjutada iteratiivset koodi jĂ€rjestikusemas ja sĂŒnkroonse sarnases stiilis, muutes selle lugemise ja mĂ”istmise lihtsamaks.
- Lihtsustatud asĂŒnkroonne programmeerimine: Generaatoreid saab kasutada asĂŒnkroonse koodi lihtsustamiseks, muutes tagasikutsete ja promise'ide haldamise lihtsamaks.
- MÀluefektiivsus: Generaatorid toodavad vÀÀrtusi nÔudmisel, mis vÔib olla mÀluefektiivsem kui tervete andmekogumite loomine ja mÀlus hoidmine.
- Kohandatud iteraatorid: Generaatorid muudavad kohandatud iteraatorite loomise keerukate andmestruktuuride vÔi algoritmide jaoks lihtsaks.
- Koodi taaskasutatavus: Generaatoreid saab koostada ja taaskasutada erinevates kontekstides, edendades koodi taaskasutatavust ja hooldatavust.
KokkuvÔte
JavaScripti generaatorid on vĂ”imas tööriist kaasaegses JavaScripti arenduses. Need pakuvad lĂŒhikest ja elegantset viisi iteraatori protokolli rakendamiseks, asĂŒnkroonse programmeerimise lihtsustamiseks ja suurte andmekogumite tĂ”husaks töötlemiseks. Generaatorite ja nende tĂ€iustatud tehnikate valdamisega saate kirjutada loetavamat, hooldatavamat ja jĂ”udlusvĂ”imelisemat koodi. Olgu tegemist keerukate andmestruktuuride ehitamise, asĂŒnkroonsete operatsioonide töötlemise vĂ”i andmete voogedastusega, generaatorid aitavad teil lahendada laia valikut probleeme kerguse ja elegantsiga. Generaatorite omaksvĂ”tt kahtlemata tĂ€iustab teie JavaScripti programmeerimisoskusi ja avab uusi vĂ”imalusi teie projektidele.
JĂ€tkates JavaScripti avastamist, pidage meeles, et generaatorid on vaid ĂŒks osa puslest. Nende kombineerimine teiste kaasaegsete funktsioonidega nagu promise'id, async/await ja noolefunktsioonid vĂ”ib viia veelgi vĂ”imsama ja vĂ€ljendusrikkama koodini. JĂ€tkake katsetamist, jĂ€tkake Ă”ppimist ja jĂ€tkake imeliste asjade ehitamist!