Node js tretira datoteku kao stream. NodeJS. Šta su tokovi i baferi? Promjena i prilagođavanje podataka

Kako koristiti

Prvo, trebate preuzeti arhivu dodataka sa stranice programera i raspakirati je u direktorij na vašoj web stranici. Dostupne su dvije verzije - minimizirana (proizvodna verzija) i za programere (razvojna verzija). U verziji za programere, tekst dodatka je predstavljen u strukturiranom obliku s komentarima, što je pogodno za razumijevanje principa rada (izvorni kod za lekciju sadrži verziju dodatka za programere s prevedenim komentarima).

Zatim u sekciju na stranici na kojoj planirate koristiti filtriranje, potrebno je umetnuti kod za vezu dodatka:

$(document).ready(function() ( $("element_for_filtering").liveFilter("option"); ));

Morate zamijeniti “/path_to_plugin/” putanjom na kojoj se plugin nalazi liveFilter, koji ste ranije raspakovali. Također morate zamijeniti “filter_element” sa CSS selektorom koji odgovara željenom elementu.

Parametar dodatka "opcija" kontroliše upotrebu animacije prilikom sakrivanja i prikazivanja elemenata tokom filtriranja. Dostupne su sljedeće vrijednosti: osnovne - elementi se jednostavno isključuju/uključuju bez ikakve animacije, slajd - filtrirani elementi će biti skupljeni/prošireni, fade - filtrirani elementi će se postepeno uključivati/isključivati.

Na primjer:

$(ul#filter_me).liveFilter("slajd");

Gornji kod govori dodatku LiveFilter da filtrira neuređenu listu sa id " filter_me” i koristite animaciju “ slajd”.

Dodatak se može koristiti za neuređene i uređene liste i tabele. Morate navesti traženi selektor kada pozivate dodatak.

Bitan! Da bi dodatak funkcionisao, potrebno je da stranici dodate polje za unos teksta sa klasom "filter". Ovo polje će se koristiti za unos teksta za filtriranje:

Primjer stranice koja koristi filter:

Primjer korištenja dodatka LiveFilter $(document).ready(function() ( $(ul#filter_me").liveFilter("slide"); ));

  • Tačka br. 1.
  • Tačka br. 2.
  • Tačka br. 3.
  • Tačka br. 4.
  • Tačka br. 5.
  • Tačka br. 6.
  • Tačka br. 7.
  • Tačka br. 8.
  • Tačka br. 9.
  • Tačka br. 10.

Plugin code

(function($)( $.fn.liveFilter = funkcija (aType) ( // Odredite šta će biti filtrirano. var filterTarget = $(ovo); var dijete; if ($(this).is("ul")) ( dijete = "li"; ) else if ($(this).is("ol")) ( dijete = "li"; ) else if ($(this).is("table")) ( dijete = " tbody tr"; ) // Definiraj varijable var hide; var show; var filter; // Događaj za ulazni element $("input.filter").keyup(function() ( // Dobij filter vrijednosti filter = $( this) .val(); // Dobijte ono što treba sakriti, a šta prikazati hide = $(filterTarget).find(child + ":not(:Contains("" + filter + ""))") ; show = $(filterTarget).find(child + ":Contains("" + filter + "")") // Animirajte stavke koje treba sakriti i prikazati if (aType == "basic") ( sakriti. hide() ; show.show(); ) else if (aType == "slide") ( hide.slideUp(500); show.slideDown(500); ) else if (aType == "fade") ( sakriti. fadeOut(400 ); show.fadeIn(400); ) )); // Prilagođeni izraz za tekstualnu funkciju neosjetljivu na velika i mala slova sadrži() jQuery.expr[":"].Sadrži = function(a,i,m)( return jQuery(a ).text().toLowerCase().indexOf(m.toLowerCase())>=0; ); ) ))(jQuery);



nodejs stream (3)

Mislim da pretjerujete kako sve to funkcionira, i to mi se sviđa.

Koji su tokovi dobri

Teme su dobre za dvije stvari:

    kada je operacija spora i može vam dati djelomične rezultate kada ih dobijete. Na primjer, pročitajte datoteku, ona je spora jer su tvrdi diskovi spori i može vam dati dio datoteke dok je čita. Sa streamovima možete koristiti ove dijelove datoteke i odmah ih početi obraditi.

    oni također dobro povezuju programe (funkcije čitanja). Kao i u komandna linija, možete kombinovati različiti programi da biste dobili željeni rezultat. Primjer: mačka datoteka | grep word cat datoteka | grep word .

Kako rade ispod haube...

Većina ovih operacija za koje je potrebno vrijeme za obradu i koje vam mogu dati djelimične rezultate dok ih dobijete ne radi Node.js, već ih radi V8 JS Engine i one samo prosljeđuju te rezultate JS-u kako biste s njima mogli raditi.

Da biste razumjeli vaš http primjer, morate razumjeti kako http funkcionira

Postoje različita kodiranja koja web stranica može poslati. U početku je postojao samo jedan način. Kada je cijela stranica poslana kada je tražena. Sada postoje efikasnija kodiranja za ovo. Jedna je fragmentacija, što znači da se dijelovi web stranice šalju prije nego što se pošalje cijela stranica. Ovo je dobro jer se web stranica može obraditi kako je primljena. Zamislite web pretraživač. Može početi prikazivati ​​web stranice prije nego što se učitavanje završi.

Vaša pitanja i odgovori.

Prvo, Node.js niti se pokreću samo u jednom Node.js programu. Node.js niti ne mogu komunicirati s niti na drugom serveru ili čak unutar programa.

To znači da u primjeru ispod, Node.js ne može razgovarati sa web serverom. Ne može reći da prestane ili da počne ponovo.

Node.js mrežni web server

Ono što se zaista događa je da Node.js zatraži web stranicu i ona počinje da je učitava i ne postoji način da se to učitavanje zaustavi. Samo uklonite utičnicu.

Dakle, šta se zapravo dešava kada uradite .pause ili .continue u Node.js?

Počinje baferovati zahtjev dok ne budete spremni da ga ponovo koristite. Ali preuzimanje nikada nije prestalo.

Petlja događaja

Imam cijeli odgovor da objasnim kako funkcionira Petlja događaja, ali mislim da vam je bolje.

Prva stvar koju treba napomenuti je da stream.js tokovi nisu ograničeni na HTTP zahtjeve. HTTP zahtjevi/mrežni resursi su samo jedan primjer toka u node.js.

Niti su korisne za sve što se može obraditi u malim komadima. Oni vam omogućavaju da obrađujete potencijalno ogromne resurse u malim komadima koji se lakše uklapaju u vaš RAM.

Recimo da imate fajl (veličine nekoliko gigabajta) i želite sve da konvertujete mala slova u velika slova i rezultat zapisati u drugu datoteku. Naivan pristup bi pročitao cijeli fajl koristeći fs.readFile (rukovanje greškama je izostavljeno radi kratkoće):

fs. readFile ("my_huge_file" , funkcija (err , data ) ( var convertedData = data . toString (). toUpperCase (); fs . writeFile ( "my_converted_file" , convertedData ); ));

Nažalost, ovaj pristup će lako preopteretiti vašu RAM memoriju jer se cijela datoteka mora sačuvati prije nego što se može obraditi. Također gubite dragocjeno vrijeme čekajući da se datoteka pročita. Zar nema smisla obrađivati ​​fajl u malim komadima? Možete započeti obradu čim primite prve bajtove, čekajući do HDDće dati preostale podatke:

var readStream = fs . createReadStream("my_huge_file"); var writeStream = fs . createWriteStream("my_converted_file"); readStream. on ("podaci", funkcija (komad) ( var convertedChunk = chunk . toString (). toUpperCase (); writeStream . write ( convertedChunk ); )); readStream. on ("kraj", funkcija () (writeStream. kraj (); ));

Ovaj pristup je mnogo bolji:

  • Radit ćete samo s malim dijelovima podataka koji će se lako uklopiti u vašu RAM memoriju.
  • Počinjete s obradom čim stigne prvi bajt i ne gubite vrijeme ne radeći ništa osim čekanja.
  • Kada se stream otvori, node.js će otvoriti datoteku i početi čitati iz nje. Jednom kada operativni sistem prenese neke bajtove u tok koji čita fajl, on će biti prenet zajedno sa vašom aplikacijom.

    Vraćanje na HTTP prijenose:

  • Prvi problem je također relevantan ovdje. Napadač vam možda šalje velike količine podataka da preoptereti vašu RAM memoriju i DoS (DoS) vašu uslugu.
  • Međutim, drugi problem je u ovom slučaju još važniji: mreža može biti vrlo spora (mislimo na pametne telefone) i može potrajati dugo da sve pošalje klijent. Koristeći stream, možete započeti obradu zahtjeva i smanjiti vrijeme odgovora.
  • Prilikom pauziranja HTTP toka: Ovo se ne radi na HTTP nivou, već ispod. Ako pauzirate stream, node.js će jednostavno prestati čitati iz osnovnog TCP soketa. Šta će se tada desiti zavisi od kernela. I dalje može baferovati dolazne podatke tako da je spreman za vas čim završite sa svojim trenutnim poslom. . Aplikacije se ne moraju baviti ovim. To se njih ne tiče. U stvari, pošiljaočeva aplikacija vjerovatno ni ne shvaća da više ne čitate aktivno!

    Dakle, u osnovi pruža podatke čim postanu dostupni, ali bez preopterećenja resursa. Glavni težak posao je obavljen operativni sistem(npr. net , fs , http) ili od autora toka koji se koristi (npr. zlib koji je Transform stream i obično je vezan za fs ili net).

    Čini se da je sljedeći dijagram prilično tačan pregled/dijagram od 10.000 stopa za klasu nodalnog toka.

    Posljednje ažuriranje: 17.11.2018

    Stream predstavlja tok podataka. Postoje potoci razne vrste, među kojima možemo razlikovati niti za čitanje i niti za pisanje.

    Prilikom kreiranja servera u prvom poglavlju, već smo naišli na nizove:

    Const http = zahtijevaju("http"); http.createServer(funkcija(zahtjev, odgovor)( )).listen(3000);

    Parametri zahtjeva i odgovora, koji se prosljeđuju funkciji i uz pomoć kojih možemo primati podatke o zahtjevu i upravljati odgovorom, su upravo tokovi: zahtjev je tok za čitanje, a odgovor je tok za pisanje.

    Koristeći tokove čitanja i pisanja, možemo čitati i pisati informacije u datoteku. Na primjer:

    Const fs = require("fs"); neka writeableStream = fs.createWriteStream("hello.txt"); writeableStream.write("Zdravo svijete!"); writeableStream.write("Nastavi snimanje \n"); writeableStream.end("Završi snimanje"); neka readableStream = fs.createReadStream("hello.txt", "utf8"); readableStream.on("data", function(chunk)( console.log(chunk); ));

    Za kreiranje toka za pisanje koristi se metoda fs.createWriteStream() kojoj se prosljeđuje ime datoteke. Ako odjednom nema takve datoteke u fascikli, onda se kreira.

    Podaci se pišu metodom write(), kojoj se podaci prenose. Za završetak snimanja poziva se metoda end().

    Nakon toga, u fascikli projekta se pojavljuje datoteka hello.txt, koja se može otvoriti u bilo kojem uređivaču teksta.

    Da kreirate tok za čitanje, koristite metodu fs.createReadStream(), kojoj se također prosljeđuje ime datoteke. Kodiranje se ovdje prosljeđuje kao opcijski parametar, koji će vam omogućiti da odmah kodirate pročitane podatke u niz u specificiranom kodiranju prilikom čitanja.

    Sam potok je podijeljen na nekoliko dijelova ili komada. I kada se čita svaki takav dio, događa se događaj podataka. Koristeći on() metodu, možemo se pretplatiti na ovaj događaj i ispisati svaki dio podataka na konzoli:

    ReadableStream.on("data", function(chunk)( console.log(chunk); ));

    Pokrenimo fajl za izvršenje:

    Funkcionalnost streamova nije ograničena na rad s datotekama; postoje i mrežni tokovi, tokovi šifriranja, arhivski tokovi itd., ali opšti principi rad sa njima će biti isti kao i sa tokovima datoteka.



    Nedavno je objavljena verzija 10.5.0 platforme Node.js. Jedna od njegovih glavnih karakteristika bila je podrška za rad sa nitima koja je po prvi put dodata u Node.js, koja je još uvijek eksperimentalna. Ova činjenica je posebno zanimljiva u svjetlu činjenice da ovu priliku sada platforma čiji su pristalice oduvek bili ponosni na činjenicu da joj nisu potrebne niti, zahvaljujući fantastičnom asinhronom I/O podsistemu. Međutim, podrška za niti se konačno pojavila u Node.js. Zašto se to dogodilo? Ko ih može koristiti i zašto?

    Ukratko, ovo je neophodno kako bi Node.js platforma mogla dostići nove visine u onim oblastima u kojima je ranije pokazivala manje od zvjezdanih rezultata. Govorimo o izvođenju proračuna koji intenzivno koriste resurse procesora. Ovo je u osnovi razlog zašto se Node.js ne razlikuje jake pozicije u oblastima kao što su veštačka inteligencija, mašinsko učenje, obrada velikih količina podataka. Mnogo je truda uloženo kako bi se omogućilo Node.js-u da se dobro ponaša u rješavanju takvih problema, ali ovdje ova platforma i dalje izgleda mnogo skromnije nego, na primjer, u razvoju mikroservisa.

    Autor materijala, čiji prijevod danas objavljujemo, kaže da je odlučio da tehničku dokumentaciju koja se nalazi u originalnom pull requestu iu , svede na niz jednostavnih praktičnih primjera. Nada se da će svako ko uzme ove primjere naučiti dovoljno da počne s nitima u Node.js.

    O modulu worker_threads i zastavici --experimental-worker Podrška za višenitnost u Node.js implementirana je u obliku modula worker_threads. Stoga, kako bi iskoristili nova prilika, ovaj modul mora biti uključen pomoću naredbe require.

    Imajte na umu da možete raditi samo sa worker_threads koristeći -- eksperimentalni-worker zastavicu kada pokrećete skriptu, inače sistem neće pronaći ovaj modul.

    Imajte na umu da zastavica uključuje riječ "worker" umjesto "thread". Upravo tako se spominje ono o čemu govorimo u dokumentaciji, u kojoj se koriste termini “worker thread” ili jednostavno “worker”. I ubuduće ćemo se pridržavati istog pristupa.

    O zadacima koji se mogu riješiti korištenjem radnika u Node.js Radničke niti su dizajnirane, kao što je već spomenuto, za rješavanje problema koji intenzivno koriste mogućnosti procesora. Treba napomenuti da je njihovo korištenje za rješavanje I/O problema gubljenje resursa, budući da su, prema službenoj dokumentaciji, interni mehanizmi Node.js-a usmjereni na organiziranje asinhronog I/O-a sami po sebi mnogo efikasniji od njihovog korištenja. za rješavanje istog problema radnih niti. Stoga ćemo odmah odlučiti da se nećemo baviti unosom i izlazom podataka pomoću radnika.

    Počnimo s jednostavnim primjerom koji pokazuje kako kreirati i koristiti radnike.

    Primjer #1 const ( Worker, isMainThread, workerData ) = require("worker_threads"); neka currentVal = 0; neka intervali = funkcija counter(id, i)( console.log("[", id, "]", i) return i; ) if(isMainThread) ( console.log("ovo je glavna nit") for( neka je i = 0; i< 2; i++) { let w = new Worker(__filename, {workerData: i}); } setInterval((a) =>currentVal = counter(a,currentVal + 1), intervali, "MainThread"); ) else ( console.log("ovo nije") setInterval((a) => currentVal = counter(a,currentVal + 1), intervali, workerData); )
    Izlaz ovog koda će izgledati kao niz linija koje prikazuju brojače koji povećavaju vrijednost s različitim brzinama.


    Rezultati prvog primjera

    Hajde da shvatimo šta se ovde dešava:

  • Instrukcije unutar if naredbe stvaraju 2 niti, kod za koji je, zahvaljujući parametru __filename, preuzet iz iste skripte koja je proslijeđena Node.js-u prilikom pokretanja primjera. Sada radnicima treba puna putanja do datoteke koda, oni ne podržavaju relativne putanje, zbog čega se ova vrijednost koristi ovdje.
  • Podaci se šalju ova dva radnika kao globalni parametar, u obliku atributa workerData, koji se koristi u drugom argumentu. Nakon toga pristupite datu vrijednost može se dobiti putem konstante s istim imenom (obratite pažnju kako se odgovarajuća konstanta kreira u prvom redu datoteke, a kako se koristi u posljednjem redu).
  • Ovo pokazuje vrlo jednostavan primjer korištenja modula worker_threads, ovdje se još ništa zanimljivo ne događa. Stoga, razmotrimo još jedan primjer.Primjer br.2 Razmotrimo primjer u kojem ćemo, prvo, izvesti neke “teške” kalkulacije, a drugo, uraditi nešto asinhrono u glavnoj niti.

    Const ( Worker, isMainThread, parentPort, workerData ) = require("worker_threads"); const request = require("zahtjev"); if(isMainThread) ( console.log("Ovo je glavna nit") neka w = new Worker(__filename, (workerData: null)); w.on("message", (msg) => ( //Poruka od worker! console.log("Prva vrijednost je: ", msg.val); console.log("Trebalo: ", (msg.timeDiff / 1000), " sekundi"); )) w.on("error", console.error); w.on("exit", (code) => ( if(code != 0) console.error(new Error(`Radnik zaustavljen sa izlaznim kodom $(code)`)) )); zahtjev .get("http://www.google.com", (err, resp) => ( if(err) ( return console.error(err); ) console.log("Ukupno primljenih bajtova: ", odn. body.length); )) ) else ( // funkcija koda radnika random(min, max) ( return Math.random() * (max - min) + min ) const sorter = require("./list-sorter") const start = Date.now() neka bigList = Array(1000000).fill().map((_) => random(1,10000)) sorter.sort(bigList); parentPort.postMessage(( val: sorter .firstValue, timeDiff: Date.now() - početak)); )
    Da biste sami pokrenuli ovaj primjer, imajte na umu da je ovom kodu potreban modul zahtjeva (može se instalirati pomoću npm-a, na primjer, korištenjem naredbi npm init --yes i npm u praznom direktoriju s datotekom koja sadrži gornji kod za instalaciju request --save), i činjenica da koristi pomoćni modul, povezan sa komandom const sorter = require("./list-sorter"); . Fajl ovog modula (list-sorter.js) treba da se nalazi na istom mestu kao i gore opisani fajl, njegov kod izgleda ovako:

    Module.exports = ( firstValue: null, sort: function(list) (nek sorted = list.sort(); this.firstValue = sorted)
    Ovog puta paralelno rješavamo dva problema. Prvo, učitavamo početnu stranicu google.com, a drugo sortiramo nasumično generiran niz od milion brojeva. Ovo može potrajati nekoliko sekundi, što nam daje sjajnu priliku da vidimo nove mehanizme Node.js u akciji. Osim toga, ovdje mjerimo vrijeme koje je potrebno radnoj niti da sortira brojeve, a zatim šaljemo rezultat mjerenja (zajedno sa prvim elementom sortiranog niza) glavnoj niti, koja rezultate ispisuje na konzolu.


    Rezultat drugog primjera

    U ovom primjeru, najvažnije je demonstrirati mehanizam za razmjenu podataka između niti.
    Radnici mogu primati poruke iz glavne teme zahvaljujući on metodi. U kodu možete pronaći događaje koje slušamo. Događaj poruke se poziva svaki put kada objavimo poruku iz niti pomoću metode parentPort.postMessage. Dodatno, isti metod se može koristiti za slanje poruka u nit, pristupanje instanci radnika i njihovo primanje pomoću parentPort objekta.

    Pogledajmo sada još jedan primjer, vrlo sličan onome što smo već vidjeli, ali ovog puta ćemo se fokusirati na Posebna pažnja strukturu projekta.

    Primjer br. 3 Kao završni primjer, predlažemo da razmotrimo implementaciju iste funkcionalnosti kao u prethodnom primjeru, ali ovog puta ćemo poboljšati strukturu koda, učiniti ga čišćim i dovesti ga u oblik koji povećava pogodnost podrške softverskom projektu.

    Evo koda za glavni program.

    Const ( Worker, isMainThread, parentPort, workerData ) = require("worker_threads"); const request = require("zahtjev"); funkcija startWorker(path, cb) ( neka w = new Worker(path, (workerData: null)); w.on("message", (msg) => (cb(null, msg) )) w.on(" error", cb); w.on("exit", (code) => ( if(code != 0) console.error(new Error(`Radnik zaustavljen sa izlaznim kodom $(code)`)) )); return w; ) console.log("ovo je glavna nit") let myWorker = startWorker(__dirname + "/workerCode.js", (err, rezultat) => ( if(err) return console.error(err); console.log("[]") console.log("Prva vrijednost je: ", result.val); console.log("Uzelo: ", (result.timeDiff / 1000), " sekundi"); )) const početak = Datum.sada(); request.get("http://www.google.com", (err, resp) => ( if(err) ( return console.error(err); ) console.log("Ukupno primljenih bajtova: ", resp .body.length); //myWorker.postMessage((finished: true, timeDiff: Date.now() - start)) //ovako možete slati poruke radniku ))
    A evo i koda koji opisuje ponašanje radničke niti (u gornjem programu, put do datoteke sa ovim kodom se formira pomoću konstrukcije __dirname + "/workerCode.js"):

    Const ( parentPort ) = require("worker_threads"); funkcija random(min, max) ( return Math.random() * (max - min) + min ) const sorter = require("./list-sorter"); const start = Date.now() let bigList = Array(1000000).fill().map((_) => random(1,10000)) /** //evo kako dobiti poruku iz glavne niti: parentPort.on ("message", (msg) => ( console.log("Glavna nit završena na: ", (msg.timeDiff / 1000), " seconds..."); )) */ sorter.sort( bigList); parentPort.postMessage(( val: sorter.firstValue, timeDiff: Date.now() - početak));
    Evo karakteristika ovog primjera:

  • Sada se kod za glavnu nit i radnu nit nalaze u različitim datotekama. To olakšava održavanje i proširenje projekta.
  • Funkcija startWorker vraća novu instancu radnika, koja omogućava da se poruke šalju ovom radniku iz glavne niti, ako je potrebno.
  • Nema potrebe provjeravati da li se kod izvodi na glavnoj niti (uklonili smo if naredbu sa odgovarajućom provjerom).
  • Radnik prikazuje komentirani fragment koda koji demonstrira mehanizam za primanje poruka iz glavne niti, koji, uzimajući u obzir već razmotreni mehanizam za slanje poruka, omogućava vam da organizirate dvosmjernu asinkronu razmjenu podataka između glavne niti radne niti.
  • Rezultati U ovom materijalu mi, na praktični primjeri, pogledali smo karakteristike korišćenja novih funkcija za rad sa streamovima u Node.js. Ako ste savladali ono što je ovdje pokriveno, spremni ste da počnete eksperimentirati s modulom worker_threads nakon što pogledate dokumentaciju. Vjerovatno je također vrijedno napomenuti da se ova funkcija upravo pojavila u Node.js-u, dok je još eksperimentalna, tako da se nešto u njenoj implementaciji može promijeniti tokom vremena. Osim toga, ako tokom vlastitih eksperimenata s worker_threads naiđete na greške ili otkrijete da bi ovaj modul mogao koristiti neku funkciju koja nedostaje, obavijestite programere o tome i pomozite poboljšanju platforme Node.js.

    Dragi čitaoci! Šta mislite o podršci za više niti u Node.js? Planirate li koristiti ovu funkciju u svojim projektima?