Node.js Generators & Võrdle tagasihelistamisega
⚡ Nutikas kokkuvõte
GeneratorNode.js-i s-d on funktsioonid, mille täitmise saab nõudmisel peatada ja jätkata. Märksõna yield peatab funktsiooni, järgmine meetod jätkab seda ja see sidumine tasandab sügavalt pesastatud tagasihelistamisfunktsioonid loetavaks järjestikuseks koodiks.

Selles ülevaates vaatleme generaatoreid ja seda, kuidas need erinevad tagasihelistustest.
Mis on generaatorid?
Generators sai populaarseks Node.js selle pärast, milleks nad võimelised on.
- Generators on funktsioonide täitmised, mida saab peatada ja hiljem jätkata.
- Generators on kasulikud selliste kontseptsioonide puhul nagu „laisk täitmine“. Täitmise peatamise ja suvalise jätkamise abil hangitakse väärtused ainult siis, kui neid vaja on.
Generatorneil on kaks peamist meetodit allpool.
- Saagise meetod — kutsutakse funktsiooni sees välja, et peatada täitmine täpselt sellel real, kus
yieldilmub. - Järgmine meetod — kutsutakse välja põhirakendusest, et jätkata funktsiooni, mis on andnud tulemuseks tulemuse. Täitmine jätkub kuni järgmise käivituseni
yieldvõi kuni funktsiooni lõpuni.
Vaatame näidet generaatorite kasutamise kohta. Näide defineerib lihtsa liitmisfunktsiooni, mis liidab kaks arvu, peatades täitmise erinevates punktides, et näidata generaatorite käitumist.
function* Add(x) { yield x + 1; // The value passed into the second next() call lands here var y = yield(null); return x + y; } var gen = Add(5); gen.next(); // runs to the first yield, returns { value: 6, done: false } gen.next(6); // resumes, y becomes 6, returns { value: 11, done: true }
Code Selgitus
- Esimene samm on generaatori funktsiooni defineerimine. Pange tähele
*lisatudfunctionmärksõna. Funktsiooni nimetatakseAddja võtab parameetrix. - .
yieldmärksõna on generaatoritele omane ja peatab funktsiooni täitmise keskel. Täitmine peatub siin kuninext()kutsutakse esile. - 2.
yieldnii peatab funktsiooni kui ka saab väärtuse: mis iganes järgmisele edastataksenext()kõnest saab väärtusy. - Üleskutse
gen.next()esimesel korral käivitatakse funktsioon esimeseyieldHelistadesgen.next(6)jätkab seda, määrab 6-leyja tagastabx + y.
⚠️ Parandus: algne nimekiri sisaldas rida y = 6 kohe pärast var y = yield(null);See omistamine kirjutab üle mis tahes väärtuse. next() tarvikud, mis muudab näite eesmärgi kehtetuks ja muudab teise yield mõttetu. Väärtus antakse nüüd läbi gen.next(6), mis ongi see, kuidas generaator helistajalt andmeid saab.
Tagasihelistamised vs generaatorid
Generatorlahendavad probleemi, mida tuntakse tagasihelistuspõrguna. Tagasihelistusfunktsioonid jäävad Node.js rakenduse arendamise käigus mõnikord nii sügavale pesasse, et neid on raske jälgida.
Siin tulevad appi generaatorid. Üks levinumaid näiteid on taimerifunktsioonide loomine. Allolev näide loob lihtsa ajanihkefunktsiooni ja kutsub selle seejärel välja viivitustega 1000, 2000 ja 3000 ms.
Step 1) Defineeri tagasihelistusfunktsioon vajaliku ajanihke koodiga.
function Timedelay(ptime, callback) { setTimeout(function() { callback("Pausing for " + ptime); }, ptime); // the delay must use ptime, the parameter name }
Code Selgitus
- Funktsioon nimega
Timedelayluuakse parameetrigaptime, mis näitab millisekundite arvu, milleks paus teha. setTimeoutootab nii mitu millisekundit ja seejärel kutsub esile antud tagasihelistamise.
⚠️ Parandus: algne kood läbis time teise argumendina setTimeout, aga nimetamata muutujat time eksisteerib — parameeter on ptimeNagu kirjutatud, viskab see ReferenceError: time is not defined.
Step 2) Nüüd vaatleme koodi, mis kasutab tagasihelistusi. 1000, 2000 ja 3000 millisekundi pikkuste viivituste aheldamiseks paigutatakse tagasihelistused üksteise sisse.
Timedelay(1000, function(message) { console.log(message); Timedelay(2000, function(message) { console.log(message); Timedelay(3000, function(message) { console.log(message); }); }); });
Code Selgitus
Timedelaykutsutakse tagasihelistusfunktsioonina, mille väärtuseks on 1000.- Selle tagasihelistamise sees
Timedelaynimetatakse uuesti numbriga 2000. - Selle sees
Timedelaykutsutakse kolmandat korda numbriga 3000.
⚠️ Parandus: iga tagasihelistamine algses logis msg, aga parameetri nimi on messageKõik kolm rida viskasid ReferenceError: msg is not defined.
Ülaltoodud koodist näete, et iga täiendava kõnega muutub see segasemaks – see pesastamine ongi see, mida tagasihelistamise põrgu kirjeldab.
Step 3) Nüüd vaadake sama käitumist generaatoritega kirjutatuna. Jada loetakse kolme tasase joonena, mitte kolme pesastamise tasemena.
function* Messages() { console.log(yield Timedelay(1000)); console.log(yield Timedelay(2000)); console.log(yield Timedelay(3000)); }
Code Selgitus
- Generaatori funktsioon on defineeritud kutsuma
Timedelayfunktsiooni. yieldkasutatakse koosTimedelayja parameetri väärtuseks 1000.yieldkasutatakse uuesti koos arvuga 2000 ja veel kord koos arvuga 3000.
⚠️ Parandus: originaal kirjutas console,log(...) komaga punkti asemel kõigil kolmel real, mis on süntaksiviga ja takistab faili täielikku parsimist.
Kuidas joosta a Generator jooksja funktsiooniga
Ülaltoodud generaator loeb ilusti, aga ei tee ise midagi. See on detail, mida enamik selgitusi ei maini, ja see on põhjus, miks tasane versioon võib tunduda maagiline. Generaator on pausil masin ja midagi peab nuppu pidevalt all hoidma. Helistamine Messages() loob lihtsalt generaatori objekti ja tagastab kohe tulemuse; taimerit ei käivitata ja midagi ei prindita.
Puuduv tükk on jooksja: väike funktsioon, mis kutsub esile next(), ootab asünkroonse töö lõppu ja seejärel kutsub next() jälle tulemusega.
// Timedelay now hands its result back to the runner function Timedelay(ptime) { return function(resume) { setTimeout(function() { resume("Pausing for " + ptime); }, ptime); }; } // The runner drives the generator to completion function run(generatorFunction) { var it = generatorFunction(); function step(value) { var result = it.next(value); if (result.done) return; // result.value is the function returned by Timedelay result.value(step); } step(); } run(Messages);
Selle toimimiseks on vaja kolme punkti. Esiteks, Timedelay ei võta enam otse tagasihelistust vastu; see tagastab funktsiooni, mida käivitaja saab käivitada, andes juhtimise tagasi, kui taimer käivitub. Teiseks, it.next(value) edastab eelmise tulemuse peatatud generaatorisse, mis võimaldab yield ülesande paremal küljel ilmuma. Kolmandaks peatub jooksja niipea, kui result.done saab tõeks, seega rekursioon lõpeb loomulikult. See jooksja muster on täpselt see, mida teegid, näiteks co, pakkusid, ja see on mehhanism, mis async/await hiljem imendus see keelde endasse.
Generators vs async/await: Kumba kasutada
Generatorolid standardne viis lameda asünkroonse koodi kirjutamiseks enne async/await eksisteeris ja neil kahel on sama põhiidee funktsiooni poolelijätmiseks. Sõlm on toetanud async/await natiivselt alates versioonist 7.6, mis muudab soovitust kõigile, kes täna uut tööd alustavad.
| Aspekt | Generators | asünkrooni/oota |
|---|---|---|
| Jooksjat vaja | Jah, teie või raamatukogu kirjutatud | Ei, see on keelde sisse ehitatud |
| Märksõna peatamine | yield |
await |
| Viga käsitlemisel | Jooksja peab vead edastama | Tavaline katse ja püüdmine |
| Võib pooleli pausi teha | Jah, ja seda saab valikuliselt jätkata | Ei, jookseb lõpuni |
| Parim on | Laisad järjestused ja lõpmatud vooged | Tavaline asünkroonne töö |
Kasutama async/await uue koodi asünkroonse voo jaoks, kuna see eemaldab jooksja ja taastab tavalise try and catch'i. Hoidke generaatorid alles ainult selleks, mida nad hästi teevad: väärtuste laisk genereerimine, pikkade või lõpmatute järjestuste itereerimine ja iga juhtum, kus tarbija otsustab täpselt, millal järgmine väärtus arvutatakse.
ühine Generator Vead ja kuidas neid parandada
Enamik generaatori probleeme tekib funktsiooni inertsuse unustamisest kuni miski kutsub esile funktsiooni next()või väikestest süntaksilibistustest tärni ümber. Iga allpool olev sümptom nimetab selle põhjuse ja lahenduse.
- Generaatori kutsumisel ei juhtu midagi: Selle kutsumine tagastab iteraatori, mitte tulemuse.
next()või anna see jooksjale edasi. - Süntaksiviga saagikuse kohta: tärn puudub.
yieldkehtib ainult seespoolfunction*. - Väärtus funktsioonist next() saabub määratlemata kujul: 1.
next()kutse ei saa väärtust edastada, kuna generaator pole veel saavutanudyieldveel. Saatke andmeid alates teisest kõnest. - Lõpmatu tsükkel jooksjas:
result.doneseda ei kontrollita kunagi, seeganext()kutsutakse välja ka pärast lõppu. Tagasta alati, kui „done” on tõene. - Vead kaovad vaikselt: Asünkroonse sammu sees olevat tagasilükkamist ei edastata kunagi generaatorile tagasi. Edastage see
it.throw(err)nii et generaatori sees kirjutatud try and catch seda tegelikult näeb ja käsitleb.




