Raziščite Web Streams API za učinkovito obdelavo podatkov v JavaScriptu. Naučite se ustvarjati, preoblikovati in uporabljati tokove za boljšo zmogljivost in upravljanje pomnilnika.
Web Streams API: Učinkoviti cevovodi za obdelavo podatkov v JavaScriptu
Web Streams API ponuja zmogljiv mehanizem za obdelavo pretočnih podatkov v JavaScriptu, kar omogoča učinkovite in odzivne spletne aplikacije. Namesto da bi nalagali celotne nabore podatkov v pomnilnik naenkrat, tokovi omogočajo postopno obdelavo podatkov, s čimer se zmanjša poraba pomnilnika in izboljša zmogljivost. To je še posebej uporabno pri delu z velikimi datotekami, omrežnimi zahtevami ali viri podatkov v realnem času.
Kaj so spletni tokovi (Web Streams)?
V svojem bistvu Web Streams API ponuja tri glavne vrste tokov:
- ReadableStream: Predstavlja vir podatkov, kot so datoteka, omrežna povezava ali generirani podatki.
- WritableStream: Predstavlja cilj za podatke, kot so datoteka, omrežna povezava ali baza podatkov.
- TransformStream: Predstavlja cevovod za preoblikovanje med ReadableStream in WritableStream. Med pretokom skozi tok lahko spreminja ali obdeluje podatke.
Te vrste tokov skupaj ustvarjajo učinkovite cevovode za obdelavo podatkov. Podatki tečejo iz ReadableStream, preko izbirnih TransformStream-ov in na koncu v WritableStream.
Ključni koncepti in terminologija
- Kosi (Chunks): Podatki se obdelujejo v ločenih enotah, imenovanih kosi. Kos je lahko katera koli vrednost v JavaScriptu, na primer niz, število ali objekt.
- Krmilniki (Controllers): Vsaka vrsta toka ima ustrezen objekt krmilnika, ki ponuja metode za upravljanje toka. Na primer, ReadableStreamController omogoča dodajanje podatkov v čakalno vrsto toka, medtem ko WritableStreamController omogoča obravnavo dohodnih kosov.
- Povezovanje (Pipes): Tokove je mogoče povezati z metodama
pipeTo()
inpipeThrough()
.pipeTo()
poveže ReadableStream z WritableStream, medtem kopipeThrough()
poveže ReadableStream s TransformStream in nato z WritableStream. - Protitlak (Backpressure): Mehanizem, ki potrošniku omogoča, da proizvajalcu sporoči, da ni pripravljen sprejeti več podatkov. To preprečuje preobremenitev potrošnika in zagotavlja, da se podatki obdelujejo z vzdržno hitrostjo.
Ustvarjanje ReadableStream
ReadableStream lahko ustvarite z uporabo konstruktorja ReadableStream()
. Konstruktor kot argument sprejme objekt, ki lahko določa več metod za nadzor obnašanja toka. Najpomembnejši med njimi sta metoda start()
, ki se pokliče ob ustvarjanju toka, in metoda pull()
, ki se pokliče, ko tok potrebuje več podatkov.
Tukaj je primer ustvarjanja ReadableStream, ki generira zaporedje števil:
const readableStream = new ReadableStream({
start(controller) {
let counter = 0;
function push() {
if (counter >= 10) {
controller.close();
return;
}
controller.enqueue(counter++);
setTimeout(push, 100);
}
push();
},
});
V tem primeru metoda start()
inicializira števec in določi funkcijo push()
, ki doda število v čakalno vrsto toka in se nato po kratkem premoru ponovno pokliče. Metoda controller.close()
se pokliče, ko števec doseže 10, kar signalizira, da je tok končan.
Uporaba ReadableStream
Za uporabo podatkov iz ReadableStream lahko uporabite ReadableStreamDefaultReader
. Bralnik ponuja metode za branje kosov iz toka. Najpomembnejša med njimi je metoda read()
, ki vrne obljubo (promise), ki se razreši z objektom, ki vsebuje kos podatkov in zastavico, ki označuje, ali je tok končan.
Tukaj je primer uporabe podatkov iz ReadableStream, ustvarjenega v prejšnjem primeru:
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();
V tem primeru funkcija read()
prebere kos iz toka, ga zabeleži v konzolo in se nato ponovno pokliče, dokler tok ni končan.
Ustvarjanje WritableStream
WritableStream lahko ustvarite z uporabo konstruktorja WritableStream()
. Konstruktor kot argument sprejme objekt, ki lahko določa več metod za nadzor obnašanja toka. Najpomembnejše med njimi so metoda write()
, ki se pokliče, ko je kos podatkov pripravljen za pisanje, metoda close()
, ki se pokliče, ko se tok zapre, in metoda abort()
, ki se pokliče, ko se tok prekine.
Tukaj je primer ustvarjanja WritableStream, ki vsak kos podatkov zabeleži v konzolo:
const writableStream = new WritableStream({
write(chunk) {
console.log('Writing:', chunk);
return Promise.resolve(); // Označuje uspeh
},
close() {
console.log('Stream closed');
},
abort(err) {
console.error('Stream aborted:', err);
},
});
V tem primeru metoda write()
zabeleži kos v konzolo in vrne obljubo, ki se razreši, ko je kos uspešno zapisan. Metodi close()
in abort()
zabeležita sporočila v konzolo, ko se tok zapre oziroma prekine.
Pisanje v WritableStream
Za pisanje podatkov v WritableStream lahko uporabite WritableStreamDefaultWriter
. Pisalec ponuja metode za pisanje kosov v tok. Najpomembnejša med njimi je metoda write()
, ki kot argument sprejme kos podatkov in vrne obljubo, ki se razreši, ko je kos uspešno zapisan.
Tukaj je primer pisanja podatkov v WritableStream, ustvarjen v prejšnjem primeru:
const writer = writableStream.getWriter();
async function writeData() {
await writer.write('Hello, world!');
await writer.close();
}
writeData();
V tem primeru funkcija writeData()
zapiše niz "Hello, world!" v tok in ga nato zapre.
Ustvarjanje TransformStream
TransformStream lahko ustvarite z uporabo konstruktorja TransformStream()
. Konstruktor kot argument sprejme objekt, ki lahko določa več metod za nadzor obnašanja toka. Najpomembnejša med njimi je metoda transform()
, ki se pokliče, ko je kos podatkov pripravljen za preoblikovanje, in metoda flush()
, ki se pokliče, ko se tok zapre.
Tukaj je primer ustvarjanja TransformStream, ki vsak kos podatkov pretvori v velike črke:
const transformStream = new TransformStream({
transform(chunk, controller) {
controller.enqueue(chunk.toUpperCase());
},
flush(controller) {
// Izbirno: Izvedite končne operacije, ko se tok zapira
},
});
V tem primeru metoda transform()
pretvori kos v velike črke in ga doda v čakalno vrsto krmilnika. Metoda flush()
se pokliče, ko se tok zapira, in se lahko uporabi za izvedbo končnih operacij.
Uporaba TransformStream-ov v cevovodih
TransformStream-i so najbolj uporabni, ko so povezani v verigo za ustvarjanje cevovodov za obdelavo podatkov. Metodo pipeThrough()
lahko uporabite za povezavo ReadableStream s TransformStream in nato z WritableStream.
Tukaj je primer ustvarjanja cevovoda, ki bere podatke iz ReadableStream, jih pretvori v velike črke z uporabo TransformStream in jih nato zapiše v 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);
V tem primeru metoda pipeThrough()
poveže readableStream
s transformStream
, nato pa metoda pipeTo()
poveže transformStream
z writableStream
. Podatki tečejo iz ReadableStream, skozi TransformStream (kjer se pretvorijo v velike črke) in nato v WritableStream (kjer se zapišejo v konzolo).
Protitlak
Protitlak je ključen mehanizem v Web Streams, ki preprečuje, da bi hiter proizvajalec preobremenil počasnega potrošnika. Ko potrošnik ne more slediti hitrosti, s katero se podatki proizvajajo, lahko proizvajalcu sporoči, naj upočasni. To se doseže preko krmilnika toka in objektov bralnika/pisalca.
Ko je notranja čakalna vrsta ReadableStream polna, se metoda pull()
ne bo poklicala, dokler v vrsti ni na voljo prostora. Podobno lahko metoda write()
WritableStream-a vrne obljubo, ki se razreši šele, ko je tok pripravljen sprejeti več podatkov.
S pravilnim obravnavanjem protitlaka lahko zagotovite, da so vaši cevovodi za obdelavo podatkov robustni in učinkoviti, tudi pri obravnavanju različnih hitrosti prenosa podatkov.
Primeri uporabe
1. Obdelava velikih datotek
Web Streams API je idealen za obdelavo velikih datotek, ne da bi jih v celoti naložili v pomnilnik. Datoteko lahko berete po kosih, vsak kos obdelate in rezultate zapišete v drugo datoteko ali tok.
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) {
// Primer: Pretvorba vsake vrstice v velike črke
const lines = chunk.split('\n');
lines.forEach(line => controller.enqueue(line.toUpperCase() + '\n'));
}
});
await readableStream.pipeThrough(transformStream).pipeTo(writableStream);
console.log('File processing complete!');
}
// Primer uporabe (potreben je Node.js)
// const fs = require('fs');
// processFile('input.txt', 'output.txt');
2. Obravnava omrežnih zahtev
Web Streams API lahko uporabite za obdelavo podatkov, prejetih iz omrežnih zahtev, kot so odgovori API-jev ali dogodki, poslani s strežnika (server-sent events). To vam omogoča, da začnete obdelovati podatke takoj, ko prispejo, namesto da bi čakali na prenos celotnega odgovora.
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);
// Obdelajte prejete podatke
console.log('Received:', text);
}
} catch (error) {
console.error('Error reading from stream:', error);
} finally {
reader.releaseLock();
}
}
// Primer uporabe
// fetchAndProcessData('https://example.com/api/data');
3. Viri podatkov v realnem času
Spletni tokovi so primerni tudi za obravnavo virov podatkov v realnem času, kot so cene delnic ali odčitki senzorjev. ReadableStream lahko povežete z virom podatkov in obdelujete dohodne podatke, ko prispejo.
// Primer: Simulacija podatkovnega vira v realnem času
const readableStream = new ReadableStream({
start(controller) {
let intervalId = setInterval(() => {
const data = Math.random(); // Simulacija odčitka senzorja
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();
// Ustavite tok po 10 sekundah
setTimeout(() => {readableStream.cancel()}, 10000);
Prednosti uporabe Web Streams API
- Izboljšana zmogljivost: Postopna obdelava podatkov zmanjša porabo pomnilnika in izboljša odzivnost.
- Boljše upravljanje pomnilnika: Izogibajte se nalaganju celotnih naborov podatkov v pomnilnik, kar je še posebej uporabno pri velikih datotekah ali omrežnih tokovih.
- Boljša uporabniška izkušnja: Začnite obdelovati in prikazovati podatke prej, kar zagotavlja bolj interaktivno in odzivno uporabniško izkušnjo.
- Poenostavljena obdelava podatkov: Ustvarite modularne in ponovno uporabne cevovode za obdelavo podatkov z uporabo TransformStream-ov.
- Podpora za protitlak: Obvladujte različne hitrosti prenosa podatkov in preprečite preobremenitev potrošnikov.
Premisleki in najboljše prakse
- Obravnava napak: Implementirajte robustno obravnavo napak, da boste elegantno obvladali napake v tokovih in preprečili nepričakovano obnašanje aplikacije.
- Upravljanje z viri: Pravilno sprostite vire, ko tokovi niso več potrebni, da se izognete uhajanju pomnilnika. Uporabite
reader.releaseLock()
in zagotovite, da so tokovi ustrezno zaprti ali prekinjeni. - Kodiranje in dekodiranje: Za obravnavo besedilnih podatkov uporabite
TextEncoderStream
inTextDecoderStream
, da zagotovite pravilno kodiranje znakov. - Združljivost z brskalniki: Pred uporabo Web Streams API preverite združljivost z brskalniki in razmislite o uporabi polyfillov za starejše brskalnike.
- Testiranje: Temeljito testirajte svoje cevovode za obdelavo podatkov, da zagotovite njihovo pravilno delovanje v različnih pogojih.
Zaključek
Web Streams API ponuja zmogljiv in učinkovit način za obravnavo pretočnih podatkov v JavaScriptu. Z razumevanjem osnovnih konceptov in uporabo različnih vrst tokov lahko ustvarite robustne in odzivne spletne aplikacije, ki z lahkoto obvladujejo velike datoteke, omrežne zahteve in vire podatkov v realnem času. Implementacija protitlaka in upoštevanje najboljših praks za obravnavo napak ter upravljanje z viri bosta zagotovila, da bodo vaši cevovodi za obdelavo podatkov zanesljivi in zmogljivi. Ker se spletne aplikacije še naprej razvijajo in obdelujejo vse bolj zapletene podatke, bo Web Streams API postal bistveno orodje za razvijalce po vsem svetu.