Node.js: n streamit voivat olla monimutkaisia, mutta niiden ymmärtämiseen kannattaa käyttää aikaa.

Key Takeaways

  • Node.js: n streamit ovat perustyökalu tietojen käsittelyyn ja siirtoon, joten ne ovat ihanteellisia reaaliaikaisiin ja tapahtumapohjaisiin sovelluksiin.
  • Voit luoda kirjoitettavan virran Node.js: ssä käyttämällä fs-moduulin createWriteStream()-funktiota, joka kirjoittaa tiedot tiettyyn paikkaan.
  • Luettava, kirjoitettava, kaksisuuntainen ja muunnos ovat Node.js: n neljää stream-tyyppiä, joilla jokaisella on oma käyttötapansa ja toiminnallisuutensa.

Virta on perusohjelmointityökalu, joka käsittelee tietovirtaa. Ytimessään virta edustaa tyypillisesti tavujen peräkkäistä siirtoa pisteestä toiseen. Node.js: n virallisessa dokumentaatiossa stream määritellään abstraktiksi käyttöliittymäksi, jota voit käyttää tietojen käsittelyyn.

Tietojen siirtäminen tietokoneella tai verkon kautta on ihanteellinen streamin käyttö.

Striimit Node.js: ssä

Streamillä on ollut olennainen rooli Node.js: n menestyksessä. Ne ovat ihanteellisia reaaliaikaiseen tietojenkäsittelyyn ja tapahtumapohjaisiin sovelluksiin, jotka ovat kaksi Node.js-ajonaikaisen ympäristön näkyvää ominaisuutta.

Luodaksesi uuden streamin Node.js: ssa, sinun on käytettävä stream-sovellusliittymää, joka toimii yksinomaan merkkijonojen ja Node.js-puskuritiedot. Node.js: ssä on neljän tyyppistä virtaa: kirjoitettava, luettava, kaksisuuntainen ja muunnettava.

Kirjoitettavan streamin luominen ja käyttäminen

Kirjoitettavan streamin avulla voit kirjoittaa tai lähettää tietoja tiettyyn paikkaan. fs (tiedostojärjestelmä) -moduulissa on WriteStream-luokka, jonka avulla voit luoda uuden streamin fs.createWriteStream() toiminto. Tämä toiminto hyväksyy polun tiedostoon, johon haluat kirjoittaa tietoja, sekä valinnaisen joukon vaihtoehtoja.

const {createWriteStream} = require("fs");

(() => {
const file = "myFile.txt";
const myWriteStream = createWriteStream(file);
let x = 0;
const writeNumber = 10000;

const writeData = () => {
while (x < writeNumber) {
const chunk = Buffer.from(`${x}, `, "utf-8");
if (x writeNumber - 1) return myWriteStream.end(chunk);
if (!myWriteStream.write(chunk)) break;
x++
}
};

writeData();
})();

Tämä koodi tuo createWriteStream() toiminto, joka anonyymi nuolitoiminto käyttää sitten virran luomiseen, joka kirjoittaa tiedot tiedostoon myFile.txt. Anonyymi funktio sisältää sisäisen funktion nimeltä writeData() joka kirjoittaa dataa.

The createWriteStream() toiminto toimii puskurin kanssa ja kirjoittaa numerokokoelman (0–9 999) kohdetiedostoon. Kuitenkin, kun suoritat yllä olevan komentosarjan, se luo samaan hakemistoon tiedoston, joka sisältää seuraavat tiedot:

Nykyinen numerokokoelma päättyy numeroon 2 915, mutta sen olisi pitänyt sisältää numeroita 9 999 asti. Tämä ristiriita johtuu siitä, että jokainen WriteStream käyttää puskuria, joka tallentaa kiinteän määrän dataa kerrallaan. Jos haluat tietää, mikä tämä oletusarvo on, sinun on otettava yhteyttä highWaterMark vaihtoehto.

console.log("The highWaterMark value is: " +
myWriteStream.writableHighWaterMark + " bytes.");

Yllä olevan koodirivin lisääminen anonyymiin toimintoon tuottaa seuraavan lähdön päätteeseen:

Päätteen lähtö osoittaa, että oletusarvo highWaterMark arvo (joka on muokattavissa) on 16 384 tavua. Tämä tarkoittaa, että voit tallentaa tähän puskuriin vain alle 16 384 tavua dataa kerrallaan. Joten jopa 2 915 (sekä kaikki pilkut ja välilyönnit) edustaa maksimimäärää dataa, jonka puskuri voi tallentaa kerralla.

Ratkaisu puskurivirheeseen on käyttää stream-tapahtumaa. Virta kohtaa erilaisia ​​tapahtumia tiedonsiirtoprosessin erillisissä vaiheissa. The valua tapahtuma on sopiva vaihtoehto tähän tilanteeseen.

Vuonna writeData() toiminto yllä, kutsu WriteStreamin kirjoitus() funktio palauttaa arvon tosi, jos data (tai sisäinen puskuri) on alle highWaterMark arvo. Tämä osoittaa, että sovellus voi lähettää enemmän dataa streamiin. Kuitenkin heti kun kirjoittaa() funktio palauttaa false, silmukka katkeaa, koska sinun on tyhjennettävä puskuri.

myWriteStream.on('drain', () => {
console.log("a drain has occurred...");
writeData();
});

Asettamalla valua tapahtumakoodi yllä olevaan anonyymiin toimintoon tyhjentää WriteStreamin puskuri kun se on täynnä. Sitten se muistuttaa writeData() menetelmää, jotta se voi jatkaa tietojen kirjoittamista. Päivitetyn sovelluksen suorittaminen tuottaa seuraavan tulosteen:

Huomaa, että sovelluksen oli tyhjennettävä WriteStream-puskuri kolme kertaa sen toteuttamisen aikana. Myös tekstitiedostossa tapahtui joitain muutoksia:

Luettavan streamin luominen ja käyttäminen

Jos haluat lukea tietoja, aloita luomalla luettava tietovirta käyttämällä fs.createReadStream() toiminto.

const {createReadStream} = require("fs");

(() => {
const file = "myFile.txt";
const myReadStream = createReadStream(file);

myReadStream.on("open", () => {
console.log(`The read stream has successfully opened ${file}.`);
});

myReadStream.on("data", chunk => {
console.log("The file contains the following data: " + chunk.toString());
});

myReadStream.on("close", () => {
console.log("The file has been successfully closed.");
});
})();

Yllä oleva skripti käyttää luoReadStream() tapa käyttää tiedostoa, jonka edellinen koodi loi: myFile.txt. The luoReadStream() funktio hyväksyy tiedostopolun (joka voi olla merkkijonon, puskurin tai URL-osoitteen muodossa) ja useita valinnaisia ​​vaihtoehtoja argumenteiksi.

Nimettömässä toiminnossa on useita tärkeitä stream-tapahtumia. Siitä ei kuitenkaan ole merkkiäkään valua tapahtuma. Tämä johtuu siitä, että luettava tietovirta puskuroi tietoja vain, kun soitat stream.push (pala) toimintoa tai käytä luettavissa tapahtuma.

The avata tapahtuma käynnistyy, kun fs avaa tiedoston, josta haluat lukea. Kun liität tiedot tapahtumasta implisiittisesti jatkuvaksi virraksi, se saa virran siirtymään virtaavaan tilaan. Tämä mahdollistaa tiedon kulkemisen heti, kun se tulee saataville. Yllä olevan sovelluksen suorittaminen tuottaa seuraavan tuloksen:

Duplex-virran luominen ja käyttäminen

Duplex-virta toteuttaa sekä kirjoitettavan että luettavan virtarajapinnan, joten voit lukea ja kirjoittaa tällaiseen virtaan. Yksi esimerkki on TCP-socket, jonka luominen luottaa verkkomoduuliin.

Yksinkertainen tapa osoittaa kaksisuuntaisen virran ominaisuudet on luoda TCP-palvelin ja -asiakas, joka siirtää tietoja.

Server.js-tiedosto

const net = require('net');
const port = 5000;
const host = '127.0.0.1';

const server = net.createServer();

server.on('connection', (socket)=> {
console.log('Connection established from client.');

socket.on('data', (data) => {
console.log(data.toString());
});

socket.write("Hi client, I am server " + server.address().address);

socket.on('close', ()=> {
console.log('the socket is closed')
});
});

server.listen(port, host, () => {
console.log('TCP server is running on port: ' + port);
});

Asiakas.js-tiedosto

const net = require('net');
const client = new net.Socket();
const port = 5000;
const host = '127.0.0.1';

client.connect(port, host, ()=> {
console.log("connected to server!");
client.write("Hi, I'm client " + client.address().address);
});

client.on('data', (data) => {
console.log(data.toString());
client.write("Goodbye");
client.end();
});

client.on('end', () => {
console.log('disconnected from server.');
});

Huomaat, että sekä palvelin- että asiakaskomentosarjat käyttävät luettavaa ja kirjoitettavaa tietovirtaa viestintään (tietojen siirtämiseen ja vastaanottamiseen). Luonnollisesti palvelinsovellus käynnistyy ensin ja alkaa kuunnella yhteyksiä. Heti kun käynnistät asiakkaan, se muodostaa yhteyden palvelimeen käyttämällä TCP-portin numero.

Yhteyden muodostuksen jälkeen asiakas aloittaa tiedonsiirron kirjoittamalla palvelimelle sen avulla WriteStream. Palvelin kirjaa vastaanottamansa tiedot päätelaitteelle, jonka jälkeen se kirjoittaa tiedot WriteStreamillään. Lopuksi asiakas kirjaa vastaanottamansa tiedot lokiin, kirjoittaa lisätiedot ja katkaisee sitten yhteyden palvelimeen. Palvelin pysyy avoinna muiden asiakkaiden yhteyden muodostamista varten.

Transform-virran luominen ja käyttäminen

Muunnosvirrat ovat kaksisuuntaisia ​​virtoja, joissa lähtö liittyy tuloon, mutta eroaa siitä. Node.js: ssä on kahden tyyppisiä muunnosvirtoja: zlib- ja kryptovirrat. Zlib-virta voi pakata tekstitiedoston ja purkaa sen sitten tiedostonsiirron jälkeen.

CompressFile.js-sovellus

const zlib = require('zlib');
const { createReadStream, createWriteStream } = require('fs');

(() => {
const source = createReadStream('myFile.txt');
const destination = createWriteStream('myFile.txt.gz');

source.pipe(zlib.createGzip()).pipe(destination);
})();

Tämä yksinkertainen komentosarja ottaa alkuperäisen tekstitiedoston, pakkaa sen ja tallentaa sen nykyiseen hakemistoon. Tämä on yksinkertainen prosessi luettavan streamin ansiosta putki() menetelmä. Virtausputkistot poistavat puskurien ja putkitietojen käytön suoraan virrasta toiseen.

Ennen kuin tiedot saavuttavat skriptin kirjoitettavan virran, se vie kuitenkin pienen kiertotien zlibin createGzip()-menetelmän kautta. Tämä menetelmä pakkaa tiedoston ja palauttaa uuden Gzip-objektin, jonka kirjoitusvirta sitten vastaanottaa.

DecompressFile.js-sovellus

const zlib = require('zlib'); 
const { createReadStream, createWriteStream } = require('fs');
 
(() => {
const source = createReadStream('myFile.txt.gz');
const destination = createWriteStream('myFile2.txt');

source.pipe(zlib.createUnzip()).pipe(destination);
})();

Tämä yllä oleva komentosarja ottaa pakatun tiedoston ja purkaa sen. Jos avaat uuden myFile2.txt tiedosto, näet, että se sisältää samat tiedot kuin alkuperäinen tiedosto:

Miksi streamit ovat tärkeitä?

Virrat tehostavat tiedonsiirtoa. Luettavat ja kirjoitettavat streamit toimivat perustana, joka mahdollistaa asiakkaiden ja palvelimien välisen viestinnän sekä suurten tiedostojen pakkaamisen ja siirron.

Streamit parantavat myös ohjelmointikielten suorituskykyä. Ilman streameja tiedonsiirtoprosessista tulee monimutkaisempi, mikä vaatii enemmän manuaalista syöttöä kehittäjiltä ja aiheuttaa enemmän virheitä ja suorituskykyongelmia.