Fluxurile din Node.js pot fi complicate, dar merită să vă faceți timp pentru a le înțelege.
Recomandări cheie
- Fluxurile din Node.js sunt un instrument fundamental pentru procesarea și transferul datelor, făcându-le ideale pentru aplicații în timp real și bazate pe evenimente.
- Pentru a crea un flux care poate fi scris în Node.js, puteți utiliza funcția createWriteStream() a modulului fs, care scrie date într-o anumită locație.
- Citibil, inscriptibil, duplex și transformat sunt cele patru tipuri de fluxuri din Node.js, fiecare cu propriul caz de utilizare și funcționalitate.
Un flux este un instrument fundamental de programare care se ocupă de fluxul de date. La bază, un flux reprezintă de obicei transferul secvenţial de octeţi de la un punct la altul. Documentația oficială a lui Node.js definește un flux ca o interfață abstractă pe care o puteți folosi pentru a lucra cu date.
Transferul de date pe un computer sau printr-o rețea este o utilizare ideală a unui flux.
Fluxuri în Node.js
Fluxurile au jucat un rol esențial în succesul Node.js. Sunt ideale pentru procesarea datelor în timp real și aplicațiile bazate pe evenimente, două caracteristici proeminente ale mediului de rulare Node.js.
Pentru a crea un flux nou în Node.js, va trebui să utilizați API-ul de flux, care funcționează exclusiv cu șiruri și Datele tampon Node.js. Node.js are patru tipuri de fluxuri: inscriptibile, citibile, duplex și transformate.
Cum să creați și să utilizați un flux care poate fi scris
Un flux care poate fi scris vă permite să scrieți sau să trimiteți date într-o anumită locație. Modulul fs (sistem de fișiere) are o clasă WriteStream, pe care o puteți folosi pentru a crea un nou flux cu fs.createWriteStream() funcţie. Această funcție acceptă calea către fișierul în care doriți să scrieți date, precum și o serie opțională de opțiuni.
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();
})();
Acest cod importă createWriteStream() funcţie, care funcția săgeată anonimă apoi folosește pentru a crea un flux care scrie date în myFile.txt. Funcția anonimă conține o funcție internă numită writeData() care scrie date.
The createWriteStream() funcția funcționează cu un buffer pentru a scrie o colecție de numere (0–9.999) în fișierul destinație. Cu toate acestea, când rulați scriptul de mai sus, acesta creează un fișier în același director care conține următoarele date:
Colecția actuală de numere se termină la 2.915, dar ar fi trebuit să includă numere până la 9.999. Această discrepanță apare deoarece fiecare WriteStream utilizează un buffer care stochează o cantitate fixă de date la un moment dat. Pentru a afla care este această valoare implicită, va trebui să consultați HighWaterMark opțiune.
console.log("The highWaterMark value is: " +
myWriteStream.writableHighWaterMark + " bytes.");
Adăugarea liniei de cod de mai sus la funcția anonimă va produce următoarea ieșire în terminal:
Ieșirea terminalului arată că implicit HighWaterMark valoarea (care este personalizabilă) este de 16.384 de octeți. Aceasta înseamnă că puteți stoca doar sub 16.384 de octeți de date în acest buffer la un moment dat. Deci, până la numărul 2.915 (plus toate virgulele și spațiile) reprezintă cantitatea maximă de date pe care o poate stoca tamponul la un moment dat.
Soluția pentru eroarea bufferului este utilizarea unui eveniment de flux. Un flux întâlnește diverse evenimente în etape distincte ale procesului de transfer de date. The scurgere evenimentul este opțiunea potrivită pentru această situație.
În writeData() funcția de mai sus, apelul către Scrierea lui WriteStream() funcția returnează adevărat dacă porțiunea de date (sau bufferul intern) este sub HighWaterMark valoare. Acest lucru indică faptul că aplicația poate trimite mai multe date către flux. Cu toate acestea, de îndată ce scrie() Funcția returnează false întreruperea buclei deoarece trebuie să goliți tamponul.
myWriteStream.on('drain', () => {
console.log("a drain has occurred...");
writeData();
});
Introducerea scurgere codul evenimentului de mai sus în funcția anonimă va goli Buffer-ul WriteStream când este la capacitate maximă. Apoi, reamintește writeData() metoda, astfel încât să poată continua să scrie date. Rularea aplicației actualizate va produce următorul rezultat:
Trebuie să rețineți că aplicația a trebuit să scurgă Buffer WriteStream de trei ori în timpul executării sale. Fișierul text a suferit și unele modificări:
Cum să creați și să utilizați un flux care poate fi citit
Pentru a citi date, începeți prin a crea un flux care poate fi citit folosind fs.createReadStream() funcţie.
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.");
});
})();
Scriptul de mai sus folosește createReadStream() metoda de accesare a fișierului creat de codul anterior: myFile.txt. The createReadStream() funcția acceptă o cale de fișier (care poate fi sub forma unui șir, buffer sau URL) și mai multe opțiuni opționale ca argumente.
În funcția anonimă, există mai multe evenimente importante ale fluxului. Cu toate acestea, nu există niciun semn de scurgere eveniment. Acest lucru se datorează faptului că un flux care poate fi citit doar tamponează datele atunci când apelați stream.push (bucătură) funcția sau utilizați lizibil eveniment.
The deschis evenimentul se declanșează când fs deschide fișierul din care doriți să citiți. Când atașați date eveniment la un flux implicit continuu, determină trecerea fluxului în modul curgător. Acest lucru permite trecerea datelor imediat ce acestea devin disponibile. Rularea aplicației de mai sus produce următoarea ieșire:
Cum să creați și să utilizați un flux duplex
Un flux duplex implementează atât interfețele de flux care pot fi scrise, cât și cele care pot fi citite, astfel încât să puteți citi și scrie într-un astfel de flux. Un exemplu este un socket TCP care se bazează pe modulul de rețea pentru crearea sa.
O modalitate simplă de a demonstra proprietățile unui flux duplex este de a crea un server TCP și un client care transferă date.
Fișierul server.js
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);
});
Fișierul client.js
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.');
});
Veți observa că atât scripturile serverului, cât și ale clientului folosesc un flux care poate fi citit și scris pentru a comunica (transfer și primi date). Desigur, aplicația server rulează prima și începe să asculte pentru conexiuni. De îndată ce porniți clientul, acesta se conectează la server folosind numărul portului TCP.
După stabilirea unei conexiuni, clientul inițiază transferul de date prin scrierea pe server folosind-o WriteStream. Serverul înregistrează datele pe care le primește pe terminal, apoi scrie date folosind WriteStream. În cele din urmă, clientul înregistrează datele pe care le primește, scrie date suplimentare și apoi se deconectează de la server. Serverul rămâne deschis pentru conectarea altor clienți.
Cum să creați și să utilizați un flux de transformare
Fluxurile de transformare sunt fluxuri duplex în care ieșirea este legată de, dar diferită de intrare. Node.js are două tipuri de fluxuri Transform: fluxuri zlib și cripto. Un flux zlib poate comprima un fișier text și apoi îl poate decomprima după transferul fișierului.
Aplicația compressFile.js
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);
})();
Acest script simplu preia fișierul text original, îl comprimă și îl stochează în directorul curent. Acesta este un proces simplu datorită fluxului care poate fi citit teava() metodă. Conductele de flux elimină utilizarea bufferelor și a datelor de canalizare direct de la un flux la altul.
Cu toate acestea, înainte ca datele să ajungă în fluxul care poate fi scris în script, este nevoie de un mic ocol prin metoda createGzip() a zlib. Această metodă comprimă fișierul și returnează un nou obiect Gzip pe care fluxul de scriere îl primește apoi.
Aplicația decompressFile.js
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);
})();
Acest script de mai sus preia fișierul comprimat și îl decomprimă. Dacă deschideți noul myFile2.txt fișier, veți vedea că acesta conține aceleași date ca fișierul original:
De ce sunt importante fluxurile?
Fluxurile sporesc eficiența transferului de date. Fluxurile care pot fi citite și care pot fi scrise servesc drept fundație care permite comunicarea între clienți și servere, precum și comprimarea și transferul fișierelor mari.
Fluxurile îmbunătățesc, de asemenea, performanța limbajelor de programare. Fără fluxuri, procesul de transfer de date devine mai complex, necesitând o introducere manuală mai mare din partea dezvoltatorilor și ducând la mai multe erori și probleme de performanță.