Išnagrinėkite Web Streams API efektyviam duomenų apdorojimui JavaScript. Sužinokite, kaip kurti, transformuoti ir vartoti srautus geresniam našumui ir atminties valdymui.
Web Streams API: Efektyvūs duomenų apdorojimo konvejeriai JavaScript kalboje
Web Streams API suteikia galingą mechanizmą srautinių duomenų apdorojimui JavaScript kalboje, leidžiantį kurti efektyvias ir greitai reaguojančias interneto programas. Užuot vienu metu į atmintį įkėlus visus duomenų rinkinius, srautai leidžia apdoroti duomenis dalimis, taip sumažinant atminties sąnaudas ir pagerinant našumą. Tai ypač naudinga dirbant su dideliais failais, tinklo užklausomis ar realaus laiko duomenų srautais.
Kas yra Web srautai?
Iš esmės, Web Streams API siūlo tris pagrindinius srautų tipus:
- ReadableStream: Atstovauja duomenų šaltiniui, pavyzdžiui, failui, tinklo ryšiui ar generuojamiems duomenims.
- WritableStream: Atstovauja duomenų paskirties vietai, pavyzdžiui, failui, tinklo ryšiui ar duomenų bazei.
- TransformStream: Atstovauja transformacijos konvejeriui tarp ReadableStream ir WritableStream. Jis gali modifikuoti ar apdoroti duomenis, kai jie teka per srautą.
Šie srautų tipai veikia kartu, kad sukurtų efektyvius duomenų apdorojimo konvejerius. Duomenys teka iš ReadableStream, per pasirenkamus TransformStreams, ir galiausiai į WritableStream.
Pagrindinės sąvokos ir terminologija
- Fragmentai (Chunks): Duomenys apdorojami atskirais vienetais, vadinamais fragmentais. Fragmentas gali būti bet kokia JavaScript vertė, pavyzdžiui, eilutė, skaičius ar objektas.
- Valdikliai (Controllers): Kiekvienas srauto tipas turi atitinkamą valdiklio objektą, kuris suteikia metodus srautui valdyti. Pavyzdžiui, ReadableStreamController leidžia įtraukti duomenis į srauto eilę, o WritableStreamController leidžia apdoroti gaunamus fragmentus.
- Kanalai (Pipes): Srautus galima sujungti naudojant
pipeTo()
irpipeThrough()
metodus.pipeTo()
sujungia ReadableStream su WritableStream, opipeThrough()
sujungia ReadableStream su TransformStream, o tada su WritableStream. - Atgalinis slėgis (Backpressure): Mechanizmas, leidžiantis vartotojui pranešti gamintojui, kad jis nėra pasirengęs priimti daugiau duomenų. Tai apsaugo vartotoją nuo perkrovos ir užtikrina, kad duomenys būtų apdorojami tvariu greičiu.
ReadableStream kūrimas
Galite sukurti ReadableStream naudodami ReadableStream()
konstruktorių. Konstruktorius priima objektą kaip argumentą, kuris gali apibrėžti kelis metodus srauto elgsenai valdyti. Svarbiausi iš jų yra start()
metodas, kuris iškviečiamas sukūrus srautą, ir pull()
metodas, kuris iškviečiamas, kai srautui reikia daugiau duomenų.
Štai pavyzdys, kaip sukurti ReadableStream, kuris generuoja skaičių seką:
const readableStream = new ReadableStream({
start(controller) {
let counter = 0;
function push() {
if (counter >= 10) {
controller.close();
return;
}
controller.enqueue(counter++);
setTimeout(push, 100);
}
push();
},
});
Šiame pavyzdyje start()
metodas inicijuoja skaitiklį ir apibrėžia push()
funkciją, kuri įtraukia skaičių į srauto eilę, o po trumpos pertraukos vėl iškviečia save. Kai skaitiklis pasiekia 10, iškviečiamas controller.close()
metodas, signalizuojantis, kad srautas baigtas.
ReadableStream naudojimas
Norėdami naudoti duomenis iš ReadableStream, galite pasitelkti ReadableStreamDefaultReader
. Skaitytuvas suteikia metodus fragmentams iš srauto skaityti. Svarbiausias iš jų yra read()
metodas, kuris grąžina pažadą (promise), kuris išsipildo su objektu, turinčiu duomenų fragmentą ir vėliavėlę, nurodančią, ar srautas baigtas.
Štai pavyzdys, kaip naudoti duomenis iš ankstesniame pavyzdyje sukurto ReadableStream:
const reader = readableStream.getReader();
async function read() {
const { done, value } = await reader.read();
if (done) {
console.log('Stream complete');
return;
}
console.log('Received:', value);
read();
}
read();
Šiame pavyzdyje read()
funkcija nuskaito fragmentą iš srauto, išveda jį į konsolę ir vėl iškviečia save, kol srautas baigiasi.
WritableStream kūrimas
Galite sukurti WritableStream naudodami WritableStream()
konstruktorių. Konstruktorius priima objektą kaip argumentą, kuris gali apibrėžti kelis metodus srauto elgsenai valdyti. Svarbiausi iš jų yra write()
metodas, kuris iškviečiamas, kai duomenų fragmentas yra paruoštas rašyti, close()
metodas, kuris iškviečiamas, kai srautas uždaromas, ir abort()
metodas, kuris iškviečiamas, kai srautas nutraukiamas.
Štai pavyzdys, kaip sukurti WritableStream, kuris kiekvieną duomenų fragmentą išveda į konsolę:
const writableStream = new WritableStream({
write(chunk) {
console.log('Writing:', chunk);
return Promise.resolve(); // Indicate success
},
close() {
console.log('Stream closed');
},
abort(err) {
console.error('Stream aborted:', err);
},
});
Šiame pavyzdyje write()
metodas išveda fragmentą į konsolę ir grąžina pažadą, kuris išsipildo, kai fragmentas sėkmingai įrašytas. close()
ir abort()
metodai išveda pranešimus į konsolę, kai srautas atitinkamai uždaromas ar nutraukiamas.
Rašymas į WritableStream
Norėdami rašyti duomenis į WritableStream, galite naudoti WritableStreamDefaultWriter
. Rašytuvas suteikia metodus fragmentams į srautą rašyti. Svarbiausias iš jų yra write()
metodas, kuris priima duomenų fragmentą kaip argumentą ir grąžina pažadą, kuris išsipildo, kai fragmentas sėkmingai įrašytas.
Štai pavyzdys, kaip rašyti duomenis į ankstesniame pavyzdyje sukurtą WritableStream:
const writer = writableStream.getWriter();
async function writeData() {
await writer.write('Hello, world!');
await writer.close();
}
writeData();
Šiame pavyzdyje writeData()
funkcija įrašo eilutę „Hello, world!“ į srautą ir tada jį uždaro.
TransformStream kūrimas
Galite sukurti TransformStream naudodami TransformStream()
konstruktorių. Konstruktorius priima objektą kaip argumentą, kuris gali apibrėžti kelis metodus srauto elgsenai valdyti. Svarbiausi iš jų yra transform()
metodas, kuris iškviečiamas, kai duomenų fragmentas yra paruoštas transformuoti, ir flush()
metodas, kuris iškviečiamas, kai srautas uždaromas.
Štai pavyzdys, kaip sukurti TransformStream, kuris kiekvieną duomenų fragmentą paverčia didžiosiomis raidėmis:
const transformStream = new TransformStream({
transform(chunk, controller) {
controller.enqueue(chunk.toUpperCase());
},
flush(controller) {
// Optional: Perform any final operations when the stream is closing
},
});
Šiame pavyzdyje transform()
metodas paverčia fragmentą didžiosiomis raidėmis ir įtraukia jį į valdiklio eilę. flush()
metodas iškviečiamas, kai srautas uždaromas, ir gali būti naudojamas atlikti bet kokias galutines operacijas.
TransformStream naudojimas konvejeriuose
TransformStreams yra naudingiausi, kai sujungiami į grandinę, sukuriant duomenų apdorojimo konvejerius. Galite naudoti pipeThrough()
metodą, norėdami sujungti ReadableStream su TransformStream, o tada su WritableStream.
Štai pavyzdys, kaip sukurti konvejerį, kuris skaito duomenis iš ReadableStream, paverčia juos didžiosiomis raidėmis naudojant TransformStream, ir tada rašo juos į WritableStream:
const readableStream = new ReadableStream({
start(controller) {
controller.enqueue('hello');
controller.enqueue('world');
controller.close();
},
});
const transformStream = new TransformStream({
transform(chunk, controller) {
controller.enqueue(chunk.toUpperCase());
},
});
const writableStream = new WritableStream({
write(chunk) {
console.log('Writing:', chunk);
return Promise.resolve();
},
});
readableStream.pipeThrough(transformStream).pipeTo(writableStream);
Šiame pavyzdyje pipeThrough()
metodas sujungia readableStream
su transformStream
, o tada pipeTo()
metodas sujungia transformStream
su writableStream
. Duomenys teka iš ReadableStream, per TransformStream (kur jie paverčiami didžiosiomis raidėmis), ir tada į WritableStream (kur jie išvedami į konsolę).
Atgalinis slėgis
Atgalinis slėgis yra esminis Web Streams mechanizmas, kuris neleidžia greitam gamintojui perkrauti lėto vartotojo. Kai vartotojas negali suspėti su duomenų gamybos greičiu, jis gali signalizuoti gamintojui, kad šis sulėtintų. Tai pasiekiama per srauto valdiklį ir skaitytuvo/rašytuvo objektus.
Kai ReadableStream vidinė eilė yra pilna, pull()
metodas nebus kviečiamas, kol eilėje neatsiras laisvos vietos. Panašiai, WritableStream write()
metodas gali grąžinti pažadą, kuris išsipildo tik tada, kai srautas yra pasirengęs priimti daugiau duomenų.
Tinkamai valdydami atgalinį slėgį, galite užtikrinti, kad jūsų duomenų apdorojimo konvejeriai būtų patikimi ir efektyvūs, net ir esant kintančiam duomenų srautui.
Panaudojimo atvejai ir pavyzdžiai
1. Didelių failų apdorojimas
Web Streams API idealiai tinka apdoroti didelius failus, neįkeliant jų visų į atmintį. Galite skaityti failą fragmentais, apdoroti kiekvieną fragmentą ir rašyti rezultatus į kitą failą ar srautą.
async function processFile(inputFile, outputFile) {
const readableStream = fs.createReadStream(inputFile).pipeThrough(new TextDecoderStream());
const writableStream = fs.createWriteStream(outputFile).pipeThrough(new TextEncoderStream());
const transformStream = new TransformStream({
transform(chunk, controller) {
// Example: Convert each line to uppercase
const lines = chunk.split('\n');
lines.forEach(line => controller.enqueue(line.toUpperCase() + '\n'));
}
});
await readableStream.pipeThrough(transformStream).pipeTo(writableStream);
console.log('File processing complete!');
}
// Example Usage (Node.js required)
// const fs = require('fs');
// processFile('input.txt', 'output.txt');
2. Tinklo užklausų tvarkymas
Galite naudoti Web Streams API, kad apdorotumėte duomenis, gautus iš tinklo užklausų, pavyzdžiui, API atsakymus ar serverio siunčiamus įvykius. Tai leidžia pradėti apdoroti duomenis vos tik jiems atvykus, užuot laukus, kol bus atsiųstas visas atsakymas.
async function fetchAndProcessData(url) {
const response = await fetch(url);
const reader = response.body.getReader();
const decoder = new TextDecoder();
try {
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
const text = decoder.decode(value);
// Process the received data
console.log('Received:', text);
}
} catch (error) {
console.error('Error reading from stream:', error);
} finally {
reader.releaseLock();
}
}
// Example Usage
// fetchAndProcessData('https://example.com/api/data');
3. Realaus laiko duomenų srautai
Web Streams taip pat tinka tvarkyti realaus laiko duomenų srautus, pavyzdžiui, akcijų kainas ar jutiklių rodmenis. Galite prijungti ReadableStream prie duomenų šaltinio ir apdoroti gaunamus duomenis, kai jie atvyksta.
// Example: Simulating a real-time data feed
const readableStream = new ReadableStream({
start(controller) {
let intervalId = setInterval(() => {
const data = Math.random(); // Simulate sensor reading
controller.enqueue(`Data: ${data.toFixed(2)}`);
}, 1000);
this.cancel = () => {
clearInterval(intervalId);
controller.close();
};
},
cancel() {
this.cancel();
}
});
const reader = readableStream.getReader();
async function readStream() {
try {
while (true) {
const { done, value } = await reader.read();
if (done) {
console.log('Stream closed.');
break;
}
console.log('Received:', value);
}
} catch (error) {
console.error('Error reading from stream:', error);
} finally {
reader.releaseLock();
}
}
readStream();
// Stop the stream after 10 seconds
setTimeout(() => {readableStream.cancel()}, 10000);
Web Streams API naudojimo privalumai
- Pagerintas našumas: Apdorokite duomenis dalimis, sumažinant atminties sąnaudas ir pagerinant reagavimą.
- Patobulintas atminties valdymas: Venkite įkelti visus duomenų rinkinius į atmintį, ypač naudinga dideliems failams ar tinklo srautams.
- Geresnė vartotojo patirtis: Pradėkite apdoroti ir rodyti duomenis greičiau, suteikiant interaktyvesnę ir greičiau reaguojančią vartotojo patirtį.
- Supaprastintas duomenų apdorojimas: Kurkite modulinius ir pakartotinai naudojamus duomenų apdorojimo konvejerius naudodami TransformStreams.
- Atgalinio slėgio palaikymas: Tvarkykite kintančius duomenų srautus ir apsaugokite vartotojus nuo perkrovos.
Svarstymai ir geriausios praktikos
- Klaidų tvarkymas: Įgyvendinkite patikimą klaidų tvarkymą, kad sklandžiai apdorotumėte srautų klaidas ir išvengtumėte netikėtos programos elgsenos.
- Išteklių valdymas: Tinkamai atlaisvinkite išteklius, kai srautai nebėra reikalingi, kad išvengtumėte atminties nutekėjimo. Naudokite
reader.releaseLock()
ir užtikrinkite, kad srautai būtų uždaryti ar nutraukti, kai tinkama. - Kodavimas ir dekodavimas: Naudokite
TextEncoderStream
irTextDecoderStream
tekstiniams duomenims tvarkyti, kad užtikrintumėte tinkamą simbolių kodavimą. - Naršyklių suderinamumas: Prieš naudodami Web Streams API, patikrinkite naršyklių suderinamumą ir apsvarstykite galimybę naudoti polifilus senesnėms naršyklėms.
- Testavimas: Kruopščiai testuokite savo duomenų apdorojimo konvejerius, kad užtikrintumėte, jog jie tinkamai veikia įvairiomis sąlygomis.
Išvada
Web Streams API suteikia galingą ir efektyvų būdą tvarkyti srautinius duomenis JavaScript kalboje. Suprasdami pagrindines sąvokas ir naudodami įvairių tipų srautus, galite kurti patikimas ir greitai reaguojančias interneto programas, kurios lengvai tvarko didelius failus, tinklo užklausas ir realaus laiko duomenų srautus. Įgyvendindami atgalinį slėgį ir laikydamiesi geriausių klaidų tvarkymo ir išteklių valdymo praktikų, užtikrinsite, kad jūsų duomenų apdorojimo konvejeriai būtų patikimi ir našūs. Kadangi interneto programos toliau tobulėja ir tvarko vis sudėtingesnius duomenis, Web Streams API taps esminiu įrankiu kūrėjams visame pasaulyje.