Node.js Generators & Comparați cu apelurile inverse
⚡ Rezumat inteligent
GeneratorFuncțiile s din Node.js sunt funcții a căror execuție poate fi suspendată și reluată la cerere. Cuvântul cheie yield pune funcția în pauză, metoda next o reia, iar această asociere aplatizează apelurile inverse imbricate profund într-un cod secvențial lizibil.

În această prezentare generală, vom analiza generatoarele și cum diferă acestea de apelurile inverse.
Ce sunt generatoarele?
Generatora devenit popular în Node.js datorită a ceea ce sunt capabili să facă.
- Generators sunt execuții de funcții care pot fi suspendate și reluate la un moment ulterior.
- GeneratorSunt utile pentru concepte precum „execuție leneșă”. Prin suspendarea execuției și reluarea acesteia după bunul plac, valorile sunt extrase doar atunci când sunt necesare.
Generatorau cele două metode cheie de mai jos.
- Metoda randamentului — apelată în interiorul unei funcții pentru a opri execuția exact la linia unde
yieldapare. - Metoda următoare — apelată din aplicația principală pentru a relua o funcție care a cedat. Execuția continuă până la următoarea
yield, sau până la sfârșitul funcției.
Să vedem un exemplu despre cum pot fi utilizate generatoarele. Exemplul definește o funcție simplă de adunare care adună două numere, oprind execuția în puncte diferite pentru a arăta cum se comportă generatoarele.
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 Explicație
- Primul pas este definirea funcției generatorului. Rețineți
*adăugat lafunctioncuvânt cheie. Funcția este apelatăAddși ia un parametrux. -
yieldcuvântul cheie este specific generatoarelor și întrerupe funcția în timpul execuției. Execuția se oprește aici până cândnext()este invocat. - Al doilea
yieldambele pun funcția în pauză și primesc o valoare: orice este transmisă următoruluinext()apelul devine valoarea luiy. - apel
gen.next()prima dată rulează funcția până la primayield. Apelgen.next(6)îl reia, atribuie 6 luiy, și se întoarcex + y.
⚠️ Corecție: listarea originală conținea rândul y = 6 imediat dupa var y = yield(null);Acea atribuire suprascrie orice valoare next() provizii, ceea ce anulează scopul exemplului și face ca al doilea yield fără sens. Valoarea este acum transmisă prin gen.next(6), adică modul în care un generator primește de fapt date de la apelant.
Callback-uri vs. generatoare
Generatorrezolvă problema cunoscută sub numele de „iad de apel invers”. Funcțiile de apel invers devin uneori atât de adânc imbricate în timpul dezvoltării unei aplicații Node.js încât sunt dificil de urmărit.
Aici intervin generatoarele. Unul dintre cele mai comune exemple este crearea funcțiilor de temporizare. Exemplul de mai jos construiește o funcție simplă de întârziere și apoi o apelează cu întârzieri de 1000, 2000 și 3000 ms.
Pas 1) Definiți funcția de apel invers cu codul de întârziere necesar.
function Timedelay(ptime, callback) { setTimeout(function() { callback("Pausing for " + ptime); }, ptime); // the delay must use ptime, the parameter name }
Code Explicație
- O funcție numită
Timedelayeste creat cu un parametruptime, care conține numărul de milisecunde pentru pauză. setTimeoutașteaptă acel număr de milisecunde și apoi invocă apelul invers furnizat.
⚠️ Corecție: codul original a fost transmis time ca al doilea argument pentru setTimeout, dar nicio variabilă numită time există — parametrul este ptimeAșa cum este scris, aruncă ReferenceError: time is not defined.
Pas 2) Acum luați în considerare codul care folosește apeluri inverse. Pentru a înlănțui întârzieri de 1000, 2000 și 3000 de milisecunde, apelurile inverse se imbricau una în cealaltă.
Timedelay(1000, function(message) { console.log(message); Timedelay(2000, function(message) { console.log(message); Timedelay(3000, function(message) { console.log(message); }); }); });
Code Explicație
Timedelayeste apelată ca o funcție de apel invers cu valoarea 1000.- În interiorul acelui apel invers,
Timedelayeste apelat din nou cu 2000. - În interiorul celuilalt,
Timedelayeste apelat a treia oară cu 3000.
⚠️ Corecție: fiecare apel invers din jurnalul original msg, dar parametrul este denumit messageToate cele trei linii au aruncat ReferenceError: msg is not defined.
Din codul de mai sus puteți vedea că devine mai dezordonat cu fiecare apel suplimentar — această imbricare este ceea ce descrie iadul apelurilor inverse.
Pas 3) Acum vedeți același comportament scris cu generatoare. Secvența se citește ca trei linii plate în loc de trei niveluri de imbricare.
function* Messages() { console.log(yield Timedelay(1000)); console.log(yield Timedelay(2000)); console.log(yield Timedelay(3000)); }
Code Explicație
- O funcție generatoare este definită pentru a apela
TimedelayFuncția. yieldeste folosit cuTimedelayși 1000 ca valoare a parametrului.yieldeste folosit din nou cu 2000 și încă o dată cu 3000.
⚠️ Corecție: originalul a scris console,log(...) cu o virgulă în loc de punct pe toate cele trei linii, ceea ce reprezintă o eroare de sintaxă și împiedică analizarea fișierului.
Cum să rulezi a Generator cu o funcție Runner
Generatorul de mai sus se citește frumos, dar nu va face nimic de unul singur. Acesta este detaliul pe care majoritatea explicațiilor îl omit și este motivul pentru care versiunea plată poate părea magică. Un generator este o mașină în pauză și ceva trebuie să apese în mod repetat butonul. Apelarea Messages() pur și simplu creează obiectul generator și returnează imediat valoarea; niciun cronometru nu pornește și nimic nu este afișat.
Piesa lipsă este un alergător: o funcție mică care apelează next(), așteaptă finalizarea lucrului asincron, apoi apelează next() din nou cu rezultatul.
// 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);
Trei puncte fac acest lucru să funcționeze. În primul rând, Timedelay nu mai acceptă direct o funcție de apel invers; returnează o funcție pe care rulantul o poate invoca, redând controlul atunci când cronometrul se declanșează. În al doilea rând, it.next(value) introduce rezultatul anterior în generatorul pus în pauză, ceea ce permite yield să apară în partea dreaptă a unei sarcini. În al treilea rând, alergătorul se oprește imediat ce result.done devine adevărat, deci recursivitatea se termină natural. Acest model de alergare este exact ceea ce au furnizat biblioteci precum co și este mecanismul care async/await absorbită ulterior în limba însăși.
Generators vs async/await: Ce metodă să folosim
Generators erau metoda standard de a scrie cod asincron plat înainte async/await a existat, iar cele două au aceeași idee fundamentală de a pune în pauză o funcție la un moment dat. Node a suportat async/await nativ de la versiunea 7.6, ceea ce modifică recomandarea pentru oricine începe o nouă activitate astăzi.
| Aspect | Generators | asincron/așteaptă |
|---|---|---|
| Se caută alergător | Da, scris de tine sau de o bibliotecă | Nu, încorporat în limbaj |
| Cuvânt cheie întrerupe | yield |
await |
| Eroare de manipulare | Runner trebuie să transmită erorile | Încercare obișnuită și prindere |
| Se poate întrerupe parțial | Da, și poate fi reluat selectiv | Nu, rulează până la finalizare |
| Cel mai bun pentru | Secvențe leneșe și fluxuri infinite | Muncă asincronă obișnuită |
Utilizare async/await pentru flux asincron în codul nou, deoarece elimină generatorul și restabilește funcțiile obișnuite de tip try și catch. Păstrați generatoarele doar pentru ceea ce fac ei bine: producerea de valori în mod leneș, iterarea secvențelor mari sau infinite și orice caz în care consumatorul decide exact când este calculată următoarea valoare.
Comun Generator Erori și cum să le remediați
Majoritatea problemelor generatorului provin din uitarea faptului că funcția este inertă până când ceva o apelează. next(), sau din mici omisiuni sintactice în jurul asteriscului. Fiecare simptom de mai jos își numește cauza și remedierea.
- Nu se întâmplă nimic când generatorul este apelat: apelarea acestuia returnează un iterator, nu un rezultat.
next()sau să o dai unui alergător. - Eroare de sintaxă la randament: lipsește asteriscul.
yieldeste valabil doar în interiorul unuifunction*. - Valoarea din next() ajunge nedefinită: prima
next()apelul nu poate livra o valoare, deoarece generatorul nu a atins oyieldîncă. Trimiteți date de la al doilea apel încolo. - Bucla infinită într-un alergător:
result.donenu este niciodată verificat, decinext()este apelat în mod repetat după sfârșit. Funcția „return” este întotdeauna adevărată atunci când „done”. - Erorile dispar în tăcere: O respingere din cadrul pasului asincron nu este niciodată transmisă înapoi în generator. Transmiteți-o înainte cu
it.throw(err)astfel încât o comandă try and catch scrisă în generator să o poată vedea și gestiona.




