Node.js straumes var būt sarežģītas, taču ir vērts veltīt laiku, lai tās saprastu.

Key Takeaways

  • Node.js straumes ir būtisks rīks datu apstrādei un pārsūtīšanai, padarot tās ideāli piemērotas reāllaika un notikumu vadītām lietojumprogrammām.
  • Lai izveidotu rakstāmu straumi pakalpojumā Node.js, varat izmantot fs moduļa funkciju createWriteStream(), kas ieraksta datus noteiktā vietā.
  • Lasāms, rakstāms, dupleksais un pārveidojams ir četri Node.js straumju veidi, un katram ir savs lietošanas gadījums un funkcionalitāte.

Straume ir galvenais programmēšanas rīks, kas nodarbojas ar datu plūsmu. Tās pamatā straume parasti atspoguļo secīgu baitu pārsūtīšanu no viena punkta uz citu. Node.js oficiālajā dokumentācijā straume ir definēta kā abstrakts interfeiss, ko varat izmantot darbam ar datiem.

Datu pārsūtīšana datorā vai tīklā ir ideāla straumes izmantošana.

Straumē Node.js

Straumēm ir bijusi būtiska loma Node.js panākumos. Tie ir ideāli piemēroti reāllaika datu apstrādei un uz notikumiem balstītas lietojumprogrammas, kas ir divas ievērojamas Node.js izpildlaika vides funkcijas.

Lai pakalpojumā Node.js izveidotu jaunu straumi, jums būs jāizmanto straumes API, kas darbojas tikai ar Strings un Node.js bufera dati. Node.js ir četru veidu straumes: rakstāmas, lasāmas, dupleksas un pārveidojamas.

Kā izveidot un izmantot rakstāmu straumi

Rakstāma straume ļauj rakstīt vai nosūtīt datus uz noteiktu vietu. Fs (failu sistēmas) modulim ir WriteStream klase, kuru varat izmantot, lai izveidotu jaunu straumi ar fs.createWriteStream() funkciju. Šī funkcija pieņem ceļu uz failu, kurā vēlaties rakstīt datus, kā arī izvēles opciju masīvu.

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

Šis kods importē izveidotWriteStream() funkcija, kas anonīmās bultiņas funkcija pēc tam izmanto, lai izveidotu straumi, kas ieraksta datus failā myFile.txt. Anonīmā funkcija satur iekšējo funkciju, ko sauc writeData() kas raksta datus.

The izveidotWriteStream() funkcija darbojas ar buferi, lai mērķa failā ierakstītu skaitļu kolekciju (0–9999). Tomēr, palaižot iepriekš minēto skriptu, tajā pašā direktorijā tiek izveidots fails, kurā ir šādi dati:

Pašreizējā skaitļu kolekcija beidzas ar 2915, taču tajā vajadzēja iekļaut skaitļus līdz 9999. Šī neatbilstība rodas tāpēc, ka katrs WriteStream izmanto buferi, kurā vienlaikus tiek glabāts noteikts datu apjoms. Lai uzzinātu, kas ir šī noklusējuma vērtība, jums jākonsultējas ar HighWaterMark opciju.

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

Pievienojot iepriekš minēto koda rindiņu anonīmajai funkcijai, terminālī tiks parādīta šāda izvade:

Termināļa izvade parāda, ka noklusējuma HighWaterMark vērtība (kas ir pielāgojama) ir 16 384 baiti. Tas nozīmē, ka šajā buferī vienlaikus varat uzglabāt tikai mazāk nekā 16 384 baitus datu. Tātad līdz skaitlim 2915 (kā arī visi komati un atstarpes) ir maksimālais datu apjoms, ko buferis var saglabāt vienlaikus.

Bufera kļūdas risinājums ir izmantot straumes notikumu. Straume saskaras ar dažādiem notikumiem atsevišķos datu pārsūtīšanas procesa posmos. The notecēt pasākums ir piemērots risinājums šai situācijai.

Iekš writeData() augstāk norādīto funkciju, zvaniet uz WriteStream rakstīšana () funkcija atgriež vērtību True, ja datu daļa (vai iekšējais buferis) ir zem HighWaterMark vērtību. Tas norāda, ka lietojumprogramma var nosūtīt straumei vairāk datu. Tomēr, tiklīdz rakstīt () funkcija atgriež false, cilpa pārtrauc, jo jums ir jāiztukšo buferis.

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

Ievietojot notecēt notikuma kods iepriekš anonīmā funkcija iztukšo WriteStream buferis kad tas ir pilns. Pēc tam tas atgādina writeData() metodi, lai tā varētu turpināt rakstīt datus. Palaižot atjaunināto lietojumprogrammu, tiks parādīta šāda izvade:

Jāņem vērā, ka lietojumprogrammai bija jāiztukšo WriteStream buferis trīs reizes tās izpildes laikā. Teksta failā ir notikušas arī dažas izmaiņas:

Kā izveidot un izmantot lasāmu straumi

Lai lasītu datus, vispirms izveidojiet lasāmu straumi, izmantojot fs.createReadStream() funkciju.

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

Iepriekš minētais skripts izmanto izveidotReadStream() metode, lai piekļūtu failam, ko izveidoja iepriekšējais kods: myFile.txt. The izveidotReadStream() funkcija pieņem faila ceļu (kas var būt virknes, bufera vai URL formā) un vairākas izvēles opcijas kā argumentus.

Anonīmajā funkcijā ir vairāki svarīgi straumes notikumi. Tomēr nekas neliecina par notecēt notikumu. Tas ir tāpēc, ka lasāmā straume buferē datus tikai tad, kad zvanāt uz stream.push (gabals) funkciju vai izmantojiet lasāms notikumu.

The atvērts notikums tiek aktivizēts, kad fs atver failu, no kura vēlaties lasīt. Kad pievienojat datus notikums uz netieši nepārtrauktu straumi, tas liek straumei pāriet plūstošā režīmā. Tas ļauj datiem iziet cauri, tiklīdz tie kļūst pieejami. Palaižot iepriekš minēto lietojumprogrammu, tiek iegūta šāda izvade:

Kā izveidot un izmantot duplekso straumi

Dupleksā straume īsteno gan rakstāmās, gan lasāmās straumes saskarnes, lai jūs varētu lasīt un rakstīt šādā straumē. Viens piemērs ir TCP ligzda, kuras izveidei ir nepieciešams tīkla modulis.

Vienkāršs veids, kā demonstrēt dupleksās straumes īpašības, ir izveidot TCP serveri un klientu, kas pārsūta datus.

Server.js fails

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

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

Jūs ievērosiet, ka gan servera, gan klienta skripti saziņai (datu pārsūtīšanai un saņemšanai) izmanto lasāmu un rakstāmu straumi. Protams, vispirms palaižas servera lietojumprogramma un sāk klausīties savienojumus. Tiklīdz jūs startējat klientu, tas izveido savienojumu ar serveri, izmantojot TCP porta numurs.

Pēc savienojuma izveides klients uzsāk datu pārsūtīšanu, rakstot uz serveri, izmantojot tā WriteStream. Serveris reģistrē saņemtos datus terminālī, pēc tam ieraksta datus, izmantojot savu WriteStream. Visbeidzot, klients reģistrē saņemtos datus, ieraksta papildu datus un pēc tam atvienojas no servera. Serveris paliek atvērts, lai citi klienti varētu izveidot savienojumu.

Kā izveidot un izmantot transformācijas straumi

Transformācijas straumes ir dupleksās straumes, kurās izvade ir saistīta ar ievadi, bet atšķiras no tās. Vietnē Node.js ir divu veidu transformācijas straumes: zlib un kriptogrāfijas straumes. Zlib straume var saspiest teksta failu un pēc faila pārsūtīšanas to atspiest.

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

Šis vienkāršais skripts ņem sākotnējo teksta failu, saspiež to un saglabā to pašreizējā direktorijā. Tas ir vienkāršs process, pateicoties lasāmajai straumei caurule () metodi. Straumes cauruļvadi novērš buferu izmantošanu un pārsūta datus tieši no vienas straumes uz citu.

Tomēr, pirms dati sasniedz rakstāmo skripta straumi, ir nepieciešams neliels apvedceļš, izmantojot zlib metodi createGzip(). Šī metode saspiež failu un atgriež jaunu Gzip objektu, ko pēc tam saņem rakstīšanas straume.

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

Šis iepriekš minētais skripts ņem saspiesto failu un atspiež to. Ja atverat jauno myFile2.txt failu, redzēsit, ka tajā ir tie paši dati kā sākotnējā failā:

Kāpēc straumes ir svarīgas?

Straumes uzlabo datu pārsūtīšanas efektivitāti. Lasāmas un rakstāmas straumes kalpo kā pamats, kas nodrošina saziņu starp klientiem un serveriem, kā arī lielu failu saspiešanu un pārsūtīšanu.

Straumes uzlabo arī programmēšanas valodu veiktspēju. Bez straumēm datu pārsūtīšanas process kļūst sarežģītāks, tāpēc izstrādātājiem ir nepieciešama lielāka manuāla ievade, kā rezultātā rodas vairāk kļūdu un veiktspējas problēmu.