Când pornim prima dată programarea, aflăm că un bloc de cod se execută de sus în jos. Aceasta este programarea sincronă: fiecare operație este finalizată înainte de a începe următoarea operație. Acest lucru este minunat când faci o mulțime de lucruri care practic nu au timp pentru ca un computer să se finalizeze, cum ar fi adăugarea de numere, manipularea unui șir sau atribuirea de variabile.
Ce se întâmplă atunci când doriți să faceți ceva care durează un timp relativ lung, cum ar fi accesarea unui fișier pe disc, trimiterea unei solicitări de rețea sau așteptarea unui cronometru? În programarea sincronă, scriptul dvs. nu poate face nimic altceva în timp ce așteaptă.
Acest lucru ar putea fi bine pentru ceva simplu sau într-o situație în care veți avea mai multe instanțe ale scriptului dvs., dar pentru multe aplicații server este un coșmar.
Introduceți programarea asincronă. Într-un script asincron, codul dvs. continuă să se execute în timp ce așteaptă ceva să se întâmple, dar poate sări înapoi când ceva sa întâmplat.
Luați, de exemplu, o solicitare de rețea. Dacă faceți o solicitare de rețea către un server lent, care durează trei secunde pentru a răspunde, scriptul dvs. poate face în mod activ alte lucruri în timp ce acest server lent răspunde. În acest caz, trei secunde s-ar putea să nu pară prea mult pentru un om, dar un server ar putea răspunde la mii de alte cereri în așteptare. Deci, cum se descurcă asincronia în Node.js?
Modul cel mai de bază este printr-un apel invers. O inversare este doar o funcție care se numește atunci când o operație asincronă este finalizată. Prin convenție, funcțiile de apel invers Node.js au cel puțin un argument, greși
. Comenzile de returnare pot avea mai multe argumente (care de obicei reprezintă datele returnate la apelul de apel), dar prima va fi greși
. Așa cum ați fi ghicit, greși
păstrează un obiect de eroare (în cazul în care a apărut o eroare - mai târziu, despre aceasta).
Să aruncăm o privire la un exemplu foarte simplu. Vom utiliza modulul sistemului de fișiere încorporat al Node.js (fs
). În acest script, vom citi conținutul unui fișier text. Ultima linie a fișierului este a console.log
care ridică o întrebare: dacă executați acest script, credeți că veți vedea jurnalul înainte de a vedea conținutul fișierului text?
var fs = cer ('fs'); fs.readFile ('a-text-file.txt', // numele fișierului unui fișier text care spune "Hello!" 'utf8', // codarea fișierului, în acest caz, funcția utf-8 (err , text) // callback console.log ('Eroare:', err); // Erori, dacă există console.log ('Text:', text); // conținutul fișierului); // Va fi aceasta înainte sau după eroarea / textul? console.log ('Înregistrează acest lucru înainte sau după conținutul fișierului text?');
Deoarece aceasta este asincronă, vom vedea ultima console.log
inainte de conținutul fișierului text. Dacă aveți un fișier numit un text-fisier.txt în același director în care executați scriptul dvs. de nod, veți vedea asta greși
este nul
, și valoarea lui text
este populate cu conținutul fișierului text.
Dacă nu aveți un fișier numit un text-fisier.txt, greși
va returna un obiect Error și valoarea lui text
va fi nedefinit
. Acest lucru conduce la un aspect important al apelărilor: trebuie să vă ocupați întotdeauna de erorile dvs. Pentru a rezolva erorile, trebuie să verificați o valoare în greși
variabil; dacă există o valoare, atunci a apărut o eroare. Prin convenție, greși
argumentele nu se întorc, de obicei fals
, astfel încât să puteți verifica numai corectitudinea.
var fs = cer ('fs'); fs.readFile ('a-text-file.txt', // numele fișierului unui fișier text care spune "Hello!" 'utf8', // codarea fișierului, în acest caz, funcția utf-8 (err , text) // apelul invers dacă (err) console.error (err); // afișați o eroare la consola altceva console.log ('Text:', text); conținutul fișierului);
Acum, să presupunem că doriți să afișați conținutul a două fișiere într-o anumită ordine. Veți sfârși cu ceva de genul:
var fs = cer ('fs'); fs.readFile ('a-text-file.txt', // numele fișierului unui fișier text care spune "Hello!" 'utf8', // codarea fișierului, în acest caz, funcția utf-8 (err , text) // apelul de apel dacă (err) console.error (err); // afișați o eroare la consola altceva console.log (' astfel încât să se afișeze conținutul fișierului fs.readFile ('another-text-file.txt', // numele fișierului unui fișier text care spune "Hello!" 'utf8', // codarea fișierului, în acest caz , funcția utf-8 (eroare, text) // apelul de apel dacă (err) console.error (err); // afișează o eroare consolei altceva console.log ); // nu există nici o eroare, deci afișați conținutul fișierului););
Codul arată destul de urât și are o serie de probleme:
Încărcați fișierele succesiv; ar fi mai eficient dacă le puteți încărca ambele în același timp și puteți returna valorile când ambele au încărcat complet.
Din punct de vedere sintactic, este corect, dar dificil de citit. Observați numărul de funcții imbricate și filele în creștere. Ai putea face niște trucuri pentru a face să pară puțin mai bine, dar poate că ți-ai sacrificat lizibilitatea în alte moduri.
Nu are scop general. Acest lucru funcționează bine pentru două fișiere, dar dacă ai avea nouă fișiere uneori și alte ori 22 sau doar una? Modul în care este scris în prezent este foarte rigid.
Nu vă faceți griji, putem rezolva toate aceste probleme (și mai mult) cu async.js.
Mai întâi, să începem prin instalarea modulului async.js.
npm instala async -
Async.js poate fi folosit pentru a lipi împreună matrice de funcții în oricare dintre serii sau paralel. Să ne rescriem exemplul:
var async = necesită ('async'), //async.js modulul fs = necesită ('fs'); async.series (// executa functiile din primul argument unul dupa altul [// Primul argument este o serie de functii functionale (cb) // 'cb' este stenta pentru "callback" fs.readFile ('a- (cb) fs.readFile ('alt-text-file.txt', 'utf8', cb);, funcția (err, valori ) // Apelul "făcut" care a fost executat după ce funcțiile din matrice au fost terminate dacă (err) // Dacă au apărut erori atunci când funcțiile din array sunt executate, acestea vor fi trimise ca eroare console.error err); altfel // Dacă err este fals, atunci totul este bun console.log ('Primul fișier text:', valori [0]); console.log ('Al doilea fișier text:'; );
Aceasta funcționează aproape la fel ca exemplul anterior, încărcând secvențial fiecare fișier și diferă doar prin faptul că citește fiecare fișier și nu afișează rezultatul până când nu este completat. Codul este mai concis și mai curat decât exemplul anterior (și o vom face și mai bine mai târziu). async.series
ia o serie de funcții și le execută unul după altul.
Fiecare funcție ar trebui să aibă doar un singur argument, apelul invers (sau cb
în codul nostru). cb
ar trebui să fie executate cu același tip de argumente ca orice alt apel invers, așa că putem să-l punem în dreptul nostru fs.readFile
argumente.
În cele din urmă, rezultatele sunt trimise la apelul final, al doilea argument la async.series
. Rezultatele sunt stocate într-o matrice cu valorile corelate cu ordinea funcțiilor din primul argument al lui async.series
.
Cu async.js, manipularea erorii este simplificată, deoarece dacă întâmpină o eroare, aceasta returnează eroarea la argumentul apelului final și nu va executa alte funcții asincrone.
O funcție înrudită este async.parallel
; are aceleași argumente ca și async.series
astfel încât să puteți schimba între cele două fără a modifica restul sintaxei. Acesta este un punct bun pentru a acoperi paralele versus concurent.
JavaScript este de fapt un limbaj cu un singur fir, ceea ce înseamnă că poate face doar un singur lucru la un moment dat. Este capabil să facă niște sarcini într-un fir separat (cele mai multe funcții de I / O, de exemplu) și aici se află în joc programele asincrone cu JS. Nu confunda paralel cu concurenta.
Când executați două lucruri cu async.parallel
, nu deschideți alt fir pentru a analiza JavaScript sau pentru a face două lucruri la un moment dat - vă controlați cu adevărat când trece între funcții în primul argument al async.parallel
. Deci nu câștigi nimic prin punerea codului sincron în async.parallel.
Acest lucru este cel mai bine explicat vizual:
Iată exemplul nostru precedent scris pentru a fi paralel - singura diferență este aceea pe care o folosim async.parallel
Decat async.series
.
var async = necesită ('async'), //async.js modulul fs = necesită ('fs'); async.parallel (// executati functiile in primul argument, dar nu asteptati ca prima functie sa termine pentru a porni a doua [// Primul argument este o serie de functii functionale (cb) // 'cb' este sintagma pentru "callback" fs.readFile ('a-text-file.txt', 'utf8', cb); function (cb) fs.readFile ', cb);], functie (err, values) // Apelul "done" care a fost executat dupa ce functiile din matrice au fost terminate daca (err) // Daca au apare erori atunci cand functiile executate in array , vor fi trimise ca eroare console.error (err); altfel // Daca err este fals, atunci totul este bun console.log ('Primul fișier text:', valori [0]); console.log "Al doilea fișier text:", valori [1]););
Exemplele noastre anterioare au executat un număr fix de operații, dar ce se întâmplă dacă aveți nevoie de un număr variabil de operații asincrone? Acest lucru devine dezordonat repede dacă vă bazați doar pe callbacks și construirea limbajului obișnuit, bazându-vă pe contoarele stricate sau verificările condițiilor care ascund adevăratul sens al codului. Să aruncăm o privire la echivalentul brut al unui buclă pentru async.js.
În acest exemplu, vom scrie zece fișiere în directorul curent cu nume de fișiere secvențiale și câteva conținuturi scurte. Puteți modifica numărul modificând valoarea primului argument din async.times
. În acest exemplu, apelul pentru fs.writeFile
creează doar un greși
argument, dar async.times
funcția poate sprijini, de asemenea, o valoare de retur. La fel ca async.series, acesta este trecut la callback-ul făcut în al doilea argument ca array.
var async = necesită ('async'), fs = necesită ('fs'); async.times (10, // numărul de timp pentru a executa funcția funcțională (runCount, callback) fs.writeFile ('file -' + runCount + 'txt', // noul nume de fișier ' runCount, // conținutul noului callback de fișiere);, funcția (err) if (err) console.error (err); altceva console.log ('Wrote files';));
Este un moment bun să spunem că majoritatea funcțiilor async.js, în mod implicit, rulează în paralel, mai degrabă decât în serii. Deci, în exemplul de mai sus, acesta va începe să creeze fișierele și să raporteze când toate sunt create și scrise complet.
Aceste funcții care rulează în mod paralel implicit au o funcție de serie corolară indicată de funcția care se încheie cu, ați ghicit-o, 'Seria'. Deci, dacă ați dori să rulați acest exemplu în serie și nu în paralel, vă veți schimba async.times
la async.timesSeries
.
Pentru următorul nostru exemplu de looping, vom arunca o privire la funcția async.until. async.until
execută o funcție asincronă (în serie) până când o anumită condiție este îndeplinită. Această funcție are trei funcții ca argumente.
Prima funcție este testul în care vă întoarceți fie adevărat (dacă vreți să opriți buclă) sau false (dacă doriți să continuați buclă). Al doilea argument este funcția asincronă, iar ultimul este apelul efectuat. Aruncați o privire la acest exemplu:
var async = necesită ('async'), fs = necesită ('fs'), startTime = new Date (). async.until (funcția () // return true dacă au trecut 4 milisecunde, altfel false (și continuă să ruleze scriptul) returnează noua dată () getTime ()> (startTime + 5) runCount + = 1; fs.writeFile ('timed-file -' + runCount + '; txt'; // noul nume de fișier 'This is file number + runCount; funcția (err) if (err) console.error (err); altceva console.log ('Scrierea fișierelor.'););
Acest script va crea fișiere text noi timp de cinci milisecunde. La începutul scenariului, obținem timpul de începere în epocile milisecunde unix, iar apoi în funcția de testare obținem timpul curent și încercăm să vedem dacă este de cinci milisecunde mai mare decât timpul de pornire plus cinci. Dacă executați acest script de mai multe ori, puteți obține rezultate diferite.
Pe mașina mea, am creat între 6 și 20 de fișiere în cinci milisecunde. Interesant, dacă încercați să adăugați console.log
fie în funcția de testare, fie în funcția asincronă, veți obține rezultate foarte diferite, deoarece este nevoie de timp pentru a scrie în consola dvs. Este doar pentru a vă arăta că în software, totul are un cost de performanță!
Fiecare buclă este o structură la îndemână - vă permite să faceți ceva pentru fiecare element dintr-o matrice. În async.js, aceasta ar fi async.each
funcţie. Această funcție are trei argumente: colecția sau matricea, funcția asincronă care trebuie efectuată pentru fiecare element și apelul de apel încheiat.
În exemplul de mai jos, luăm o serie de șiruri de caractere (în acest caz tipurile de rase de câini de câini) și creăm un fișier pentru fiecare șir. Când toate fișierele au fost create, se execută apelul de apel încheiat. Așa cum v-ați putea aștepta, erorile sunt gestionate prin intermediul greși
obiect în apel invers. async.each
este rulat în paralel, dar dacă doriți să îl rulați în serie, puteți urma modelul și modul de utilizare menționat anterior async.eachSeries
in loc de async.each
.
var async = necesită ('async'), fs = necesită ('fs'); async.each (// o gamă de rase de câini de păsări ['greyhound', 'saluki', 'borzoi', 'galga', 'podenco', 'whippet', 'lurcher', 'italian-greyhound' ), funcția (err) fs.writeFile (dogBreed + '.txt', // noul nume de fișier "fișier pentru câinii din rasă" + dogBreed, // conținutul noului callback de fișiere) dacă err) console.error (err); altceva console.log ("Efectuarea de scriere a fișierelor despre câini"););
Un văr de async.each
este async.map
funcţie; diferența este că puteți trece valorile înapoi la apelul dat. Cu async.map
, treceți într-o matrice sau colecție ca primul argument și apoi o funcție asincronă va fi rulată pe fiecare element din matrice sau din colecție. Ultimul argument este apelul efectuat.
Exemplul de mai jos ia o gamă de rase de câini și utilizează fiecare element pentru a crea un nume de fișier. Numele de fișier este apoi trecut la fs.readFile
, unde este citit și valorile sunt transferate înapoi de către funcția de apel invers. Veți ajunge cu o matrice a conținutului fișierelor în argumentele de apel invocate.
var async = necesită ('async'), fs = necesită ('fs'); async.map (['greyhound', 'saluki', 'borzoi', 'galga', 'podenco', 'whippet', 'lurcher', 'italian-greyhound' (greb, dogBreedFileContents) if (err) console.error (err); altceva console.log ("dog" rase "); console.log (dogBreedFileContents););
async.filter
este, de asemenea, foarte asemănătoare în sintaxa cu async.each
și async.map
, dar cu filtru trimiteți o valoare booleană la inversarea apelului elementului mai degrabă decât valoarea fișierului. În apelul efectuat veți obține o nouă matrice, cu numai elementele pe care le-ați trecut a Adevărat
sau valoare truthy pentru inversarea elementului.
var async = necesită ('async'), fs = necesită ('fs'); async.filter (['greyhound', 'saluki', 'borzoi', 'galga', 'podenco', 'whippet', 'lurcher', 'italian-greyhound'], function (dogBreed, callback) fs.readFile ("err") callback (err); altceva callback (err, // aceasta va fi falsă de când am verificat este mai mare decât fileContents.match (/ greyhound / gi) // folosiți RegExp pentru a verifica șirul "greyhound" în conținutul fișierului);); funcția (err, dogBreedFileContents) if (err) .error (err); altceva console.log ('breeds of greyhound:'); console.log (dogBreedFileContents););
În acest exemplu, facem mai multe lucruri decât în exemplele anterioare. Observați cum adăugăm un apel suplimentar pentru funcții și care se ocupă de eroarea proprie. dacă
greși
și callback (err)
modelul este foarte util dacă trebuie să manipulați rezultatele unei funcții asincrone, dar totuși doriți să lăsați async.js să se ocupe de erori.
În plus, veți observa că folosim variabila err ca primul argument pentru funcția de apel invers. La prima blush, acest lucru nu pare destul de corect. Dar, deoarece am verificat deja corectitudinea erorii, știm că este fals și sigur să treci la callback.
Până acum, am explorat o serie de blocuri de construcție utile care au corolari brute în programarea sincronă. Hai să ne aruncăm în cap async.waterfall
, care nu are mult de echivalent în lumea sincronă.
Conceptul cu o cascadă este că rezultatele unei funcții asincrone se varsă în argumentele unei alte funcții asincrone în serie. Este un concept foarte puternic, mai ales când încercați să strângeți împreună mai multe funcții asincrone care se bazează unul pe celălalt. Cu async.waterfall
, primul argument este o serie de funcții, iar al doilea argument este apelul făcut de dvs..
În gama de funcții, prima funcție va începe întotdeauna cu un singur argument, apelul invers. Fiecare funcție ulterioară ar trebui să se potrivească cu argumentele non-err ale funcției anterioare, cu funcția err și cu adăugarea noului apel invers.
În următorul exemplu, vom începe să combinăm câteva concepte folosind cascada ca un lipici. În matricea care este primul argument, avem trei funcții: prima încarcă lista de directoare din directorul curent, cea de-a doua folosește lista și folosește directorul async.map
a alerga fs.stat
pe fiecare fișier, iar cea de-a treia funcție preia lista de directoare din primul rezultat al funcției și primește conținutul fiecărui fișier (fs.readFile
).
async.waterfall
execută fiecare funcție secvențial, astfel încât va rula întotdeauna toate fs.stat
înainte de a rula orice fs.readFile
. În acest prim exemplu, a doua și a treia funcție nu depind una de cealaltă, astfel încât să poată fi înfășurate într-un async.parallel
pentru a reduce timpul total de execuție, vom modifica din nou această structură pentru exemplul următor.
Notă: Executați acest exemplu într-un mic director de fișiere text, în caz contrar veți obține o mulțime de gunoi pentru o lungă perioadă de timp în fereastra terminalului dvs..
var async = necesită ('async'), fs = necesită ('fs'); async.waterfall ([function (callback) fs.readdir ('.', apel invers); // citeste directorul curent, transmite-l catre functia urmatoare; function (fileNames, callback) // ' este lista de director din funcția anterioară async.map (fileNames, // Listarea directoarelor este doar o serie de nume de fișiere, fs.stat, // pentru a putea folosi async.map pentru a rula fs.stat pentru fiecare funcție de nume de fișier (err , statistici) if (err) callback (err); altceva callback (err, fileNames, stats); // treceți de eroare, lista de directoare și colecția stat la următorul articol din cascadă) ;, funcția (fileNames, statistici, callback) // listarea directorului, 'fileNames' este alăturată colecției obiectelor fs.stat din 'stats' async.map (fileNames, function (aFileName, readCallback) // De data aceasta luăm numele fișierelor cu hartă și le transmitem către fs.readFile pentru a obține conținutul fs.readFile (aFileName, 'utf8', readCallback);, funcția (err, contents) if (err) callback (err); altceva // Acum callback w Există trei argumente: lista originală de directoare ("fileNames"), colecția fs.stats și o serie de conținuturi ale fiecărui apel invers (err, fileNames, statistici, conținut); ); ], funcția (err, fileNames, statistici, conținut) if (err) console.error (err); altceva console.log (fileNames); console.log (statistici); console.log (conținuturi); );
Să presupunem că vrem să obținem rezultatele numai a fișierelor care au o dimensiune de peste 500 de octeți. Am putea folosi codul de mai sus, dar veți obține dimensiunea și conținutul fiecărui fișier, indiferent dacă aveți nevoie de ele sau nu. Cum ai putut obține statul fișierelor și numai conținutul fișierelor care îndeplinesc cerințele de dimensiune?
În primul rând, putem trage toate funcțiile anonime în funcții numite. Este o preferință personală, dar face codul mai puțin curat și mai ușor de înțeles (reutilizabil la boot). După cum vă puteți imagina, va trebui să obțineți dimensiunile, să evaluați aceste dimensiuni și să obțineți numai conținutul fișierelor deasupra dimensiunii cerute. Acest lucru poate fi ușor realizat cu ceva de genul Array.filter
, dar aceasta este o funcție sincronă, iar asyncwaterfall se așteaptă ca funcții asincrone. Async.js are o funcție de ajutor care poate împacheta funcții sincrone în funcții asincrone, mai degrabă numită jazzily async.asyncify
.
Trebuie să facem trei lucruri, pe care le vom împacheta async.asyncify
. Mai întâi vom lua numele de fișier și matricele de stat din arrayFsStat
și le vom îmbina Hartă
. Apoi vom filtra toate obiectele care au o dimensiune stat mai mică de 300. În cele din urmă, vom lua numele de fișier combinat și obiectul stat și de a folosi Hartă
din nou pentru a obține numele fișierului afară.
După ce vom primi numele fișierelor cu o dimensiune mai mică de 300, vom folosi async.map
și fs.readFile
pentru a obține conținutul. Există multe modalități de a sparge acest ou, dar în cazul nostru a fost spart pentru a demonstra flexibilitatea maximă și reutilizarea codului. Acest async.waterfall
utilizarea ilustrează modul în care puteți amesteca și potrivi codul sincron și asincron.
var async = necesită ('async'), fs = necesită ('fs'); // Anonimul nostru a refactat în funcții numit directorul funcțieiList (callback) fs.readdir ('.', Callback); funcția arrayFsStat (fileNames, callback) async.map (fileNames, fs.stat, funcția (err, stats) if (err) callback (err) altceva callback (err, fileNames, stats); ); funcția arrayFsReadFile (fileNames, callback) async.map (fileNames, funcția (aFileName, readCallback) fs.readFile (aFileName, 'utf8', readCallback); (err); altceva callback (err, conținut);); // Aceste funcții sunt funcția sincronă mergeFilenameAndStat (fileNames, stats) returnează stats.map (funcția (aStatObj, index) aStatObj.fileName = fileNames [index], return aStatObj;); funcția above300 (combinateFilenamesAndStats) return combinatFilenamesAndStats .filter (funcția (aStatObj) return aStatObj.size> = 300;); funcția justFilenames (combinedFilenamesAndStats) return combinateFilenamesAndStats .map (funcția (aCombinedFileNameAndStatObj) return aCombinedFileNameAndStatObj.fileName;); async.waterfall ([directoryListing, arrayFsStat, async.asyncify (mergeFilenameAndStat), // asyncify împachetează funcțiile sincrone într-un err-first callback async.asyncify (over300), async.asyncify (justFilenames), arrayFsReadFile] conținutul) if (err) console.error (err); altceva console.log (contents););
Cu un pas mai departe, să ne perfecționăm funcția. Să presupunem că vrem să scriem o funcție care să funcționeze exact ca mai sus, dar cu flexibilitatea de a căuta în orice cale. Un văr apropiat de async.waterfall este async.seq
. In timp ce async.waterfall
execută doar o cascadă de funcții, async.seq
returnează o funcție care efectuează o cascadă a altor funcții. În plus față de crearea unei funcții, puteți trece valori care vor intra în prima funcție asincronă.
Se convertește la async.seq
au doar câteva modificări. În primul rând, vom modifica directoryListing
pentru a accepta un argument - aceasta va fi calea. În al doilea rând, vom adăuga o variabilă pentru a ține noua funcție (directoryAbove300
). În al treilea rând, vom lua argumentul de la matrice din async.waterfall
și traduceți asta în argumente pentru async.seq
. Comanda noastră de apel făcută pentru cascadă este acum utilizată ca apel invers când suntem executați directoryAbove300
.
var async = necesită ('async'), fs = necesită ('fs'), directoryAbove300; (//) putem trece o variabila in prima functie folosita in async.seq - functia rezultata poate accepta argumentele si sa le transmita aceasta prima functie fs.readdir (initialPath, callback); funcția arrayFsStat (fileNames, callback) async.map (fileNames, fs.stat, funcția (err, stats) if (err) callback (err) altceva callback (err, fileNames, stats); ); funcția arrayFsReadFile (fileNames, callback) async.map (fileNames, funcția (aFileName, readCallback) fs.readFile (aFileName, 'utf8', readCallback); (err); altceva callback (err, conținut);); funcția mergeFilenameAndStat (fileNames, stats) returnează stats.map (funcția (aStatObj, index) aStatObj.fileName = fileNames [index]; retur aStatObj;); funcția above300 (combinateFilenamesAndStats) return combinatFilenamesAndStats .filter (funcția (aStatObj) return aStatObj.size> = 300;); function justFilenames (combinateFilenamesAndStats) return combinateFilenamesAndStats .map (function (aCombinedFileNameAndStatObj) return aCombinedFileNameAndStatObj.fileName; //async.seq va produce o noua functie pe care o puteti folosi peste si peste directorAbove300 = async.seq (directoryListing, arrayFsStat, async.asyncify (mergeFilenameAndStat), async.asyncify (mai sus300), async.asyncify (justFilenames), arrayFsReadFile); directorAbove300 ('.', functie (err, fileNames, statistici, continut) if (err) console.error (err); altceva console.log (fileNames););
S-ar putea să te întrebi de ce nu am menționat promisiunile. Nu am nimic împotriva lor - sunt destul de la îndemână și poate o soluție mai elegantă decât apelurile de apel - dar sunt o modalitate diferită de a privi codificarea asincronă.
Modulele Node.js încorporate utilizează greși
-primele apeluri de apel și mii de alte module utilizează acest model. De fapt, de aceea folosește acest tutorial fs
în exemple - ceva atât de fundamental ca accesul la sistemul de fișiere în Node.js folosește callback-urile, astfel încât codurile de apel invers fără promisiuni reprezintă o parte esențială a programării Node.js.
Este posibil să utilizați ceva de genul Bluebird pentru a împacheta eror-primele callback-uri în funcții bazate pe promisiune, dar care vă devine doar atât de departe - Async.js oferă o serie de metafore care fac ca codul asincron să poată fi citit și gestionat.
JavaScript a devenit una dintre limbile de facto de lucru pe web. Nu este fără curbele sale de învățare, și există o mulțime de cadre și biblioteci pentru a vă menține ocupați. Dacă sunteți în căutarea unor resurse suplimentare pentru a studia sau a utiliza în munca dvs., verificați ce avem la dispoziție pe piața Envato.
Dar învățarea asincronă este ceva cu totul diferit și, sperăm, acest tutorial ți-a arătat cât de utilă poate fi.
Asincronia este cheia pentru scrierea JavaScript-ului de pe server, dar dacă nu este creat corect, codul dvs. poate deveni o fiară necontrolabilă a callback-urilor. Folosind o bibliotecă ca async.js care oferă un număr de metafore, s-ar putea să constatăți că scrierea codului asincron este o bucurie.