Node.js streamovi: FileStream, Pipes i događaji
⚡ Pametni sažetak
Node.js streamovi čitaju i pišu podatke u malim komadima umjesto da učitavaju cijele datoteke u memoriju, a ova stranica objašnjava stvaranje datotečnog toka, ulančavanje cijevi, rukovanje povratnim pritiskom i model događaja koji održava učinkovitim prijenos velikih količina podataka.

Vrste streamova u Node.js-u
Svaki stream koji Node.js izlaže spada u jedan od četiri osnovna tipa, a poznavanje tipa koji određeni API vraća objašnjava kako se taj stream ponaša prije nego što se napiše bilo kakav kod. Modul streama koji dolazi s Node.js-om definira ove kategorije, a API-ji za datoteke, mrežu i kompresiju korišteni u ovom članku izgrađeni su na njima.
| Vrsta toka | Smjer podataka | Primjer API-ja | Uobičajeni slučaj upotrebe |
|---|---|---|---|
| Readable | Samo izvor (podaci izlaze) | fs.createReadStream() | Čitanje datoteke, primanje tijela HTTP zahtjeva |
| Može se pisati | Samo odredište (podaci ulaze) | fs.createWriteStream() | Pisanje datoteke, slanje HTTP odgovora |
| Dvoetažni | Oba smjera, neovisno | net.Socket (TCP utičnica) | Dvosmjerna mrežna komunikacija |
| Transformirati | Oba smjera, podaci se mijenjaju tijekom prijenosa | zlib.createGzip() | Komprimiranje ili kodiranje podataka usred prijenosa |
Čitljivi stream i stream u koji se može pisati dva su gradiva koja se koriste u ovom članku; oba također pokreću HTTP web poslužitelj u Node.js-u. Dvostruki stream kombinira obje uloge u jednom objektu, dok je transformacijski stream dvostruki stream čiji izlaz modificira ulaz, poput gzip kompresije primijenjene usred streama.
Filestream u Node.js
Nakon što su definirane četiri kategorije streamova, ostatak ovog članka izrađuje prijenos datoteka pomoću API-ja streamova za čitanje i pisanje.
Node u velikoj mjeri koristi streamove kao mehanizam prijenosa podataka.
Na primjer, kada ispisujete bilo što na konzolu pomoću funkcije console.log, zapravo koristite tok za slanje podataka na konzolu.
Node.js također ima mogućnost strujanja podataka iz datoteka tako da se mogu čitati i pisati na odgovarajući način. Sada ćemo pogledati primjer kako možemo koristiti tokove za čitanje i pisanje iz datoteka. Moramo slijediti dolje navedene korake za ovaj primjer
Korak 1) Napravite datoteku pod nazivom data.txt koja sadrži podatke ispod. Pretpostavimo da je ova datoteka pohranjena na D disku našeg lokalnog stroja.
Vodič za Node.js
Uvod
Događaji
Podatkovna povezanost
Korištenje Jasmina
Korak 2) Napišite odgovarajući kod koji će koristiti streamove za čitanje podataka iz datoteke.
var fs = require("fs"); var stream; stream = fs.createReadStream("D://data.txt"); stream.on("data", function(data) { var chunk = data.toString(); console.log(chunk); });
Code Obrazloženje:-
- Najprije moramo uključiti 'fs' module koji sadrže sve funkcije potrebne za stvaranje tokova.
- Zatim stvaramo čitljiv stream pomoću metode – createReadStream. Kao unos dajemo lokaciju naše datoteke data.txt.
- Funkcija steam.on je rukovatelj događajima iu njoj navodimo prvi parametar kao 'podatke'. To znači da svaki put kada podaci dođu u tok iz datoteke, izvršite funkciju povratnog poziva. U našem slučaju, definiramo funkciju povratnog poziva koja će izvršiti 2 osnovna koraka. Prvi je pretvoriti podatke pročitane iz datoteke u niz. Drugi bi bio slanje pretvorenog niza kao izlaz na konzolu.
- Uzimamo svaki dio podataka koji se čita iz toka podataka i pretvaramo ga u niz.
- Konačno, šaljemo izlaz svakog niza pretvorenog dijela na konzolu.
Izlaz:
- Ako se kôd ispravno izvede, vidjet ćete gornji izlaz u konzoli. Ovaj izlaz će biti isti kao onaj u datoteci data.txt.
Zapisivanje u datoteku
Na isti način na koji stvaramo tok za čitanje, možemo također stvoriti tok za pisanje za pisanje podataka u datoteku. Kreirajmo prvo praznu datoteku bez sadržaja pod nazivom data.txt. Pretpostavimo da je ova datoteka smještena na D pogon našeg računala.
Donji kod pokazuje kako možemo pisati podatke u datoteku.
var fs = require("fs"); var stream; stream = fs.createWriteStream("D://data.txt"); stream.write("Tutorial on Node.js") stream.write("Introduction") stream.write("Events") stream.write("Generators") stream.write("Data Connectivity") stream.write("Using Jasmine")
Code Obrazloženje:-
- Kreiramo tok koji se može pisati korištenjem metode – createWriteStream. Kao unos dajemo lokaciju naše datoteke data.txt.
- Zatim smo upotrijebili metodu stream.write za pisanje različitih redaka teksta u našu tekstualnu datoteku. Stream će se pobrinuti za pisanje ovih podataka u datoteku data.txt.
Ako otvorite datoteku data.txt, vidjet ćete sljedeće podatke u datoteci
Vodič za Node.js
Uvod
Događaji
Generators
Podatkovna povezanost
Korištenje Jasmin
Cijevi u Node.js
Neovisno čitanje i pisanje streamova je korisno, ali Node.js također omogućuje izravno povezivanje čitljivog streama s streamom za pisanje, premještajući podatke bez ručnog međuspremničkog koda.
Unutar Node aplikacija, tokovi se mogu spojiti zajedno pomoću metode pipe(), koja uzima dva argumenta:
- Potreban tok za pisanje koji služi kao odredište za podatke i
- Neobavezni objekt koji se koristi za prosljeđivanje opcija.
Tipičan primjer korištenja cijevi, ako želite prenijeti podatke iz jedne datoteke u drugu.
Dakle, pogledajmo primjer kako možemo prenijeti podatke iz jedne datoteke u drugu pomoću cijevi.
Korak 1) Napravite datoteku pod nazivom datainput.txt koja sadrži podatke u nastavku. Pretpostavimo da je ova datoteka pohranjena na D disku našeg lokalnog stroja.
Vodič za Node.js
Uvod
Događaji
Generators
Podatkovna povezanost
Korištenje Jasmina
Korak 2) Napravite praznu praznu datoteku pod nazivom dataOutput.txt i stavite je na D pogon vašeg lokalnog računala.
Korak 3) Napišite kod u nastavku da biste izvršili prijenos podataka iz datoteke datainput.txt u datoteku dataOutput.txt.
var fs = require("fs"); var readStream = fs.createReadStream("D://datainput.txt"); var writeStream = fs.createWriteStream("D://dataOutput.txt"); readStream.pipe(writeStream);
Code Obrazloženje:-
- Prvo stvaramo "readstream" za našu datainput.txt datoteku koja sadrži sve naše podatke koje je potrebno prenijeti u novu datoteku.
- Zatim trebamo stvoriti "writestream" u našu datoteku dataOutput.txt, koja je naša prazna datoteka i odredište je za prijenos podataka iz datoteke datainput.txt.
- Zatim koristimo naredbu pipe za prijenos podataka iz toka čitanja u tok pisanja. Naredba cijevi će uzeti sve podatke koji dolaze u tok čitanja i gurnuti ih u tok pisanja.
Ako sada otvorite datoteku dataOutput.txt, vidjet ćete sve podatke koji su bili prisutni u datoteci dataOutput.txt.
Događaji streama i povratni tlak u Node.js-u
Pozivanje pipe(), kao što je gore prikazano, skriva dva mehanizma koja su važna u velikim razmjerima: događaje koje svaki stream emitira i sustav povratnog tlaka koji sprječava brzi izvor da preoptereti sporo odredište.
- podatke: emitirano od strane čitljivog streama svaki put kada je dostupan novi blok.
- kraj: emitira se nakon što čitljivi stream isporuči svoj posljednji dio.
- Završi: emitira se putem zapisivog streama nakon što se svi podaci u redu čekanja ispišu.
- pogreška: emitira ga bilo koji tip streama u slučaju kvara; uvijek ga obradi ili se proces ruši.
Primjer u nastavku osluškuje sva četiri događaja dok ručno upravlja povratnim tlakom, isto ponašanje koje pipe() pruža automatski.
var fs = require("fs"); var readStream = fs.createReadStream("D://data.txt"); var writeStream = fs.createWriteStream("D://dataOutput.txt"); readStream.on("data", function(chunk) { var ok = writeStream.write(chunk); if (!ok) { readStream.pause(); } }); writeStream.on("drain", function() { readStream.resume(); }); readStream.on("end", function() { writeStream.end(); }); writeStream.on("finish", function() { console.log("Write completed."); }); readStream.on("error", function(err) { console.log(err); });
Protivpritisak se javlja kada čitljivi stream proizvodi podatke brže nego što ih stream za pisanje može potrošiti. Metoda write() vraća false nakon što se međuspremnik napuni, pa gornji kod pauzira izvor dok odredište ne emitira događaj drain, signalizirajući da je sigurno nastaviti. pipe() automatski izvršava ovaj ciklus.
⚠ Savjet: U produkciji, preferirajte funkciju pipeline() iz modula stream u odnosu na ručni lanac pipe(), jer ona prosljeđuje pogreške iz svakog streama i automatski zatvara ručke datoteka.
Događaji u Node.js
Streamovi su jedan primjer šireg dizajna vođenog događajima u Node.js-u. Ostatak ovog članka razmatra kako događaji općenito funkcioniraju, koristeći istu klasu EventEmitter na koju se streamovi interno oslanjaju.
Događaji su jedan od ključnih koncepata u Node.js i ponekad se Node.js naziva okvirom vođenim događajima.
U osnovi, događaj je nešto što se događa. Na primjer, ako se uspostavi veza s bazom podataka, tada se pokreće događaj povezivanja s bazom podataka. Programiranje vođeno događajima je stvaranje funkcija koje će se pokrenuti kada se pokrenu određeni događaji.
Pogledajmo osnovni primjer definiranja događaja u Node.js.
Kreirat ćemo događaj pod nazivom 'data_received'. Kada se ovaj događaj pokrene, tekst "podaci su primljeni" bit će poslan na konzolu.
var events = require('events'); var eventEmitter = new events.EventEmitter(); eventEmitter.on('data_received', function() { console.log('data received succesfully.'); }); eventEmitter.emit('data_received');
Code Obrazloženje:-
- Upotrijebite funkciju require za uključivanje modula 'događaji'. Pomoću ovog modula moći ćete kreirati događaje u Node.js.
- Stvorite novi emiter događaja. Ovo se koristi za vezanje događaja, koji je u našem slučaju "data_received" na funkciju povratnog poziva koja je definirana u koraku 3.
- Definiramo funkciju vođenu događajima koja kaže da ako se pokrene događaj "data_received", tada bismo trebali poslati tekst "data_received" na konzolu.
- Konačno, imamo ručni okidač našeg događaja pomoću funkcije eventEmiter.emit. To će pokrenuti događaj data_received.
Kada se program pokrene, tekst "podaci su primljeni" bit će poslan na konzolu kao što je prikazano u nastavku.
Emitirajući događaji
Osim emitiranja i slušanja događaja, Node.js nudi dodatne metode za kontrolu načina registracije i pregleda slušatelja.
Prilikom definiranja događaja postoje različite metode za događaje koje je moguće pozvati. Ova se tema fokusira na detaljno razmatranje svakog od njih.
- Rukovatelji jednokratnim događajima
Ponekad ćete možda biti zainteresirani reagirati na događaj tek kad se prvi put dogodi. U tim situacijama možete koristiti metodu once().
Pogledajmo kako se možemo poslužiti jednom metodom za rukovatelje događajima.
Code Obrazloženje:-
- Ovdje koristimo metodu 'jednom' kako bismo rekli da se za događaj 'data_received' funkcija povratnog poziva treba izvršiti samo jednom.
- Ovdje ručno pokrećemo događaj 'data_received'.
- Kada se događaj 'data_received' ponovo pokrene, ovaj put se ništa neće dogoditi. To je zbog prvog koraka u kojem smo rekli da se događaj može pokrenuti samo jednom.
Ako se kôd ispravno izvede, izlaz u dnevniku bit će "data_received successfully". Ova poruka će se pojaviti samo jednom u konzoli.
- Provjera slušatelja događaja
U bilo kojem trenutku svog životnog vijeka emiter događaja može imati nula ili više slušatelja pridruženih sebi. Slušatelji za svaku vrstu događaja mogu se pregledati na nekoliko načina.
Ako vas zanima samo određivanje broja priloženih slušatelja, ne tražite dalje od metode EventEmitter.listenerCount().
(Bilješka: Slušatelji su važni jer bi glavni program trebao znati dodaju li se slušatelji u hodu u događaj, inače će program pokvariti jer će biti pozvani dodatni slušatelji.)
Code Obrazloženje:-
- Definiramo tip eventEmitter koji je potreban za korištenje metoda povezanih s događajima.
- Zatim definiramo objekt koji se zove emiter koji će se koristiti za definiranje naših rukovatelja događajima.
- Stvaramo 2 rukovatelja događajima koji u osnovi ne rade ništa. Ovo je jednostavno za naš primjer samo da pokaže kako metoda listenerCount radi.
- Sada kada pozovete metodu listenerCount na našem događaju data_received, ona će poslati broj slušatelja događaja priloženih ovom događaju u zapisnik konzole.
Ako se kôd ispravno izvede, vrijednost 2 bit će prikazana u zapisniku konzole.
- Događaj newListener
Svaki put kada se registrira novi rukovatelj događajima, emiter događaja emitira događaj newListener. Ovaj se događaj koristi za otkrivanje novih rukovatelja događajima. Događaj newListener obično koristite kada trebate dodijeliti resurse ili izvršiti neku radnju za svaki novi rukovatelj događajima.
var events = require('events'); var eventEmitter = events.EventEmitter; var emitter = new eventEmitter(); emitter.on("newListener", function(eventName, listener) { console.log("Added listener for " + eventName + " events"); }); emitter.on('data_received', function() {}); emitter.on('data_received', function() {});
Code Obrazloženje:-
- Stvaramo novi rukovatelj događajima za događaj 'newListener'. Dakle, kad god se registrira novi rukovatelj događajima, na konzoli će se prikazati tekst "Dodan slušatelj za" + naziv događaja.
- Ovdje upisujemo na konzolu tekst “Dodan slušatelj za” + naziv događaja za svaki registrirani događaj.
- Definiramo 2 rukovatelja događajima za naš događaj 'data_received'.
Ako se gornji kod ispravno izvede, tekst u nastavku bit će prikazan na konzoli. To samo pokazuje da je rukovatelj događajem 'newListener' dvaput pokrenut.
Dodan slušatelj za data_received događaje
Dodan slušatelj za data_received događaje









