Strømmer i Node.js kan være kompliserte, men det er verdt å ta deg tid til å forstå dem.

Viktige takeaways

  • Strømmer i Node.js er et grunnleggende verktøy for databehandling og overføring, noe som gjør dem ideelle for sanntids- og hendelsesdrevne applikasjoner.
  • For å lage en skrivbar strøm i Node.js kan du bruke fs-modulens createWriteStream()-funksjon, som skriver data til en bestemt plassering.
  • Lesbar, skrivbar, dupleks og transformasjon er de fire typene strømmer i Node.js, hver med sin egen brukssituasjon og funksjonalitet.

En strøm er et grunnleggende programmeringsverktøy som tar for seg dataflyten. I kjernen representerer en strøm typisk sekvensiell overføring av byte fra ett punkt til et annet. Node.js offisielle dokumentasjon definerer en strøm som et abstrakt grensesnitt som du kan bruke til å jobbe med data.

Overføring av data på en datamaskin eller over et nettverk er en ideell bruk av en strøm.

Strømmer i Node.js

Strømmer har spilt en viktig rolle i suksessen til Node.js. De er ideelle for sanntidsdatabehandling og hendelsesdrevne applikasjoner, to fremtredende funksjoner i Node.js runtime-miljøet.

For å opprette en ny strøm i Node.js, må du bruke strøm-API, som utelukkende fungerer med strenger og Node.js bufferdata. Node.js har fire typer strømmer: skrivbar, lesbar, dupleks og transformer.

Hvordan lage og bruke en skrivbar strøm

En skrivbar strøm lar deg skrive eller sende data til et bestemt sted. fs (filsystem)-modulen har en WriteStream-klasse, som du kan bruke til å lage en ny strøm med fs.createWriteStream() funksjon. Denne funksjonen godtar banen til filen du vil skrive data til, samt en valgfri rekke alternativer.

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();
})();

Denne koden importerer createWriteStream() funksjon, som den anonyme pilfunksjonen bruker deretter til å lage en strøm som skriver data til myFile.txt. Den anonyme funksjonen inneholder en indre funksjon kalt skriveData() som skriver data.

De createWriteStream() funksjonen fungerer med en buffer for å skrive en samling av tall (0–9 999) til målfilen. Men når du kjører skriptet ovenfor, oppretter det en fil i samme katalog som inneholder følgende data:

Den nåværende samlingen av tall ender på 2 915, men den skal ha inkludert tall opp til 9 999. Dette avviket oppstår fordi hver WriteStream bruker en buffer som lagrer en fast mengde data om gangen. For å finne ut hva denne standardverdien er, må du konsultere høyvannmerke alternativ.

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

Å legge til kodelinjen ovenfor til den anonyme funksjonen vil produsere følgende utgang i terminalen:

Terminalutgangen viser at standard høyvannmerke verdi (som kan tilpasses) er 16 384 byte. Dette betyr at du bare kan lagre under 16 384 byte med data i denne bufferen om gangen. Så opp til nummer 2915 (pluss alle kommaer og mellomrom) representerer den maksimale mengden data bufferen kan lagre på en gang.

Løsningen på bufferfeilen er å bruke en strømhendelse. En strøm møter ulike hendelser på forskjellige stadier av dataoverføringsprosessen. De avløp arrangementet er det passende alternativet for denne situasjonen.

I skriveData() funksjonen ovenfor, kallet til WriteStreams skriv() funksjonen returnerer sann hvis databiten (eller intern buffer) er under høyvannmerke verdi. Dette indikerer at applikasjonen kan sende mer data til strømmen. Imidlertid, så snart skrive() funksjonen returnerer false sløyfen bryter fordi du trenger å tømme bufferen.

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

Setter inn avløp hendelseskoden ovenfor i den anonyme funksjonen vil tømme WriteStreams buffer når den er i full kapasitet. Deretter husker den skriveData() metode, slik at den kan fortsette å skrive data. Å kjøre det oppdaterte programmet vil produsere følgende utdata:

Du bør merke deg at søknaden måtte tømme WriteStream buffer tre ganger under utførelsen. Tekstfilen opplevde også noen endringer:

Hvordan lage og bruke en lesbar strøm

For å lese data, start med å lage en lesbar strøm ved å bruke fs.createReadStream() funksjon.

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.");
});
})();

Skriptet ovenfor bruker createReadStream() metode for å få tilgang til filen som den forrige koden opprettet: myFile.txt. De createReadStream() funksjonen aksepterer en filbane (som kan være i form av en streng, buffer eller URL) og flere valgfrie alternativer som argumenter.

I den anonyme funksjonen er det flere viktige strømmehendelser. Det er imidlertid ingen tegn til avløp begivenhet. Dette er fordi en lesbar strøm bare buffere data når du ringer stream.push (bit) funksjon eller bruk leselig begivenhet.

De åpen hendelsen utløses når fs åpner filen du vil lese fra. Når du legger ved data hendelse til en implisitt kontinuerlig strøm, får den strømmen til å gå over til flytende modus. Dette gjør at data kan passere så snart de blir tilgjengelige. Å kjøre applikasjonen ovenfor gir følgende utgang:

Hvordan lage og bruke en dupleksstrøm

En dupleksstrøm implementerer både skrivbare og lesbare strømgrensesnitt, slik at du kan lese og skrive til en slik strøm. Et eksempel er en TCP-socket som er avhengig av nettmodulen for å lage den.

En enkel måte å demonstrere egenskapene til en dupleksstrøm er å lage en TCP-server og -klient som overfører data.

Server.js-filen

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);
});

Client.js-filen

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.');
});

Du vil legge merke til at både server- og klientskriptene bruker en lesbar og skrivbar strøm for å kommunisere (overføre og motta data). Naturligvis kjører serverapplikasjonen først og begynner å lytte etter tilkoblinger. Så snart du starter klienten, kobles den til serveren ved hjelp av TCP-portnummeret.

Etter å ha opprettet en tilkobling, starter klienten dataoverføring ved å skrive til serveren ved å bruke dens WriteStream. Serveren logger dataene den mottar til terminalen, og deretter skriver den data ved hjelp av WriteStream. Til slutt logger klienten dataene den mottar, skriver tilleggsdata og kobler deretter fra serveren. Serveren forblir åpen for andre klienter å koble til.

Hvordan lage og bruke en transformasjonsstrøm

Transformasjonsstrømmer er dupleksstrømmer der utgangen er relatert til, men forskjellig fra, inngangen. Node.js har to typer Transform-strømmer: zlib- og kryptostrømmer. En zlib-strøm kan komprimere en tekstfil og deretter dekomprimere den etter filoverføring.

compressFile.js-applikasjonen

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);
})();

Dette enkle skriptet tar den originale tekstfilen, komprimerer den og lagrer den i gjeldende katalog. Dette er en enkel prosess takket være de lesbare strømmene rør() metode. Strømrørledninger fjerner bruken av buffere og rørdata direkte fra en strøm til en annen.

Men før dataene når den skrivbare strømmen i skriptet, tar det en liten omvei via zlibs createGzip()-metode. Denne metoden komprimerer filen og returnerer et nytt Gzip-objekt som skrivestrømmen deretter mottar.

DecompressFile.js-applikasjonen

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);
})();

Dette skriptet ovenfor tar den komprimerte filen og dekomprimerer den. Hvis du åpner den nye minFil2.txt fil, vil du se at den inneholder de samme dataene som den opprinnelige filen:

Hvorfor er strømmer viktige?

Strømmer forbedrer effektiviteten av dataoverføring. Lesbare og skrivbare strømmer fungerer som grunnlaget som muliggjør kommunikasjon mellom klienter og servere, samt komprimering og overføring av store filer.

Strømmer forbedrer også ytelsen til programmeringsspråk. Uten strømmer blir dataoverføringsprosessen mer kompleks, og krever større manuell input fra utviklere og resulterer i flere feil og ytelsesproblemer.