Izpētiet Web Streams API efektīvai datu apstrādei JavaScript. Uzziniet, kā veidot, pārveidot un patērēt straumes uzlabotai veiktspējai un atmiņas pārvaldībai.
Web Streams API: Efektīvas datu apstrādes konveijeri JavaScript
Web Streams API nodrošina jaudīgu mehānismu straumētu datu apstrādei JavaScript, ļaujot veidot efektīvas un atsaucīgas tīmekļa lietojumprogrammas. Tā vietā, lai uzreiz ielādētu atmiņā veselas datu kopas, straumes ļauj apstrādāt datus pakāpeniski, samazinot atmiņas patēriņu un uzlabojot veiktspēju. Tas ir īpaši noderīgi, strādājot ar lieliem failiem, tīkla pieprasījumiem vai reāllaika datu plūsmām.
Kas ir Web straumes?
Savā būtībā Web Streams API nodrošina trīs galvenos straumju veidus:
- ReadableStream: Pārstāv datu avotu, piemēram, failu, tīkla savienojumu vai ģenerētus datus.
- WritableStream: Pārstāv datu galamērķi, piemēram, failu, tīkla savienojumu vai datu bāzi.
- TransformStream: Pārstāv transformācijas konveijeru starp ReadableStream un WritableStream. Tas var modificēt vai apstrādāt datus, kad tie plūst caur straumi.
Šie straumju veidi sadarbojas, lai izveidotu efektīvus datu apstrādes konveijerus. Dati plūst no ReadableStream, caur izvēles TransformStreams un visbeidzot uz WritableStream.
Galvenie jēdzieni un terminoloģija
- Datu gabali (Chunks): Dati tiek apstrādāti atsevišķās vienībās, ko sauc par datu gabaliem. Datu gabals var būt jebkura JavaScript vērtība, piemēram, virkne, skaitlis vai objekts.
- Kontrolieri (Controllers): Katram straumes veidam ir atbilstošs kontroliera objekts, kas nodrošina metodes straumes pārvaldībai. Piemēram, ReadableStreamController ļauj ievietot datus straumē, savukārt WritableStreamController ļauj apstrādāt ienākošos datu gabalus.
- Cauruļvadi (Pipes): Straumes var savienot kopā, izmantojot
pipeTo()
unpipeThrough()
metodes.pipeTo()
savieno ReadableStream ar WritableStream, savukārtpipeThrough()
savieno ReadableStream ar TransformStream un pēc tam ar WritableStream. - Pretspiediens (Backpressure): Mehānisms, kas ļauj patērētājam signalizēt ražotājam, ka tas nav gatavs saņemt vairāk datu. Tas novērš patērētāja pārslodzi un nodrošina, ka dati tiek apstrādāti ilgtspējīgā ātrumā.
ReadableStream izveide
Jūs varat izveidot ReadableStream, izmantojot ReadableStream()
konstruktoru. Konstruktors kā argumentu pieņem objektu, kurā var definēt vairākas metodes straumes uzvedības kontrolei. Svarīgākās no tām ir start()
metode, kas tiek izsaukta, kad straume tiek izveidota, un pull()
metode, kas tiek izsaukta, kad straumei nepieciešami papildu dati.
Šeit ir piemērs, kā izveidot ReadableStream, kas ģenerē skaitļu secību:
const readableStream = new ReadableStream({
start(controller) {
let counter = 0;
function push() {
if (counter >= 10) {
controller.close();
return;
}
controller.enqueue(counter++);
setTimeout(push, 100);
}
push();
},
});
Šajā piemērā start()
metode inicializē skaitītāju un definē push()
funkciju, kas ievieto skaitli straumē un pēc tam izsauc sevi vēlreiz pēc nelielas aizkaves. controller.close()
metode tiek izsaukta, kad skaitītājs sasniedz 10, signalizējot, ka straume ir pabeigta.
ReadableStream patērēšana
Lai patērētu datus no ReadableStream, varat izmantot ReadableStreamDefaultReader
. Lasītājs nodrošina metodes datu gabalu lasīšanai no straumes. Svarīgākā no tām ir read()
metode, kas atgriež solījumu (promise), kas atrisinās ar objektu, kurā ir datu gabals un karodziņš, kas norāda, vai straume ir pabeigta.
Šeit ir piemērs, kā patērēt datus no iepriekšējā piemērā izveidotās ReadableStream:
const reader = readableStream.getReader();
async function read() {
const { done, value } = await reader.read();
if (done) {
console.log('Straume pabeigta');
return;
}
console.log('Saņemts:', value);
read();
}
read();
Šajā piemērā read()
funkcija nolasa datu gabalu no straumes, reģistrē to konsolē un pēc tam izsauc sevi vēlreiz, līdz straume ir pabeigta.
WritableStream izveide
Jūs varat izveidot WritableStream, izmantojot WritableStream()
konstruktoru. Konstruktors kā argumentu pieņem objektu, kurā var definēt vairākas metodes straumes uzvedības kontrolei. Svarīgākās no tām ir write()
metode, kas tiek izsaukta, kad datu gabals ir gatavs rakstīšanai, close()
metode, kas tiek izsaukta, kad straume tiek aizvērta, un abort()
metode, kas tiek izsaukta, kad straume tiek pārtraukta.
Šeit ir piemērs, kā izveidot WritableStream, kas katru datu gabalu reģistrē konsolē:
const writableStream = new WritableStream({
write(chunk) {
console.log('Raksta:', chunk);
return Promise.resolve(); // Norāda uz veiksmīgu izpildi
},
close() {
console.log('Straume aizvērta');
},
abort(err) {
console.error('Straume pārtraukta:', err);
},
});
Šajā piemērā write()
metode reģistrē datu gabalu konsolē un atgriež solījumu, kas tiek atrisināts, kad datu gabals ir veiksmīgi ierakstīts. close()
un abort()
metodes reģistrē ziņojumus konsolē, kad straume tiek attiecīgi aizvērta vai pārtraukta.
Rakstīšana WritableStream
Lai rakstītu datus WritableStream, varat izmantot WritableStreamDefaultWriter
. Rakstītājs nodrošina metodes datu gabalu rakstīšanai straumē. Svarīgākā no tām ir write()
metode, kas kā argumentu pieņem datu gabalu un atgriež solījumu, kas tiek atrisināts, kad datu gabals ir veiksmīgi ierakstīts.
Šeit ir piemērs, kā rakstīt datus iepriekšējā piemērā izveidotajā WritableStream:
const writer = writableStream.getWriter();
async function writeData() {
await writer.write('Sveika, pasaule!');
await writer.close();
}
writeData();
Šajā piemērā writeData()
funkcija ieraksta virkni "Sveika, pasaule!" straumē un pēc tam aizver straumi.
TransformStream izveide
Jūs varat izveidot TransformStream, izmantojot TransformStream()
konstruktoru. Konstruktors kā argumentu pieņem objektu, kurā var definēt vairākas metodes straumes uzvedības kontrolei. Svarīgākā no tām ir transform()
metode, kas tiek izsaukta, kad datu gabals ir gatavs transformācijai, un flush()
metode, kas tiek izsaukta, kad straume tiek aizvērta.
Šeit ir piemērs, kā izveidot TransformStream, kas katru datu gabalu pārveido par lielajiem burtiem:
const transformStream = new TransformStream({
transform(chunk, controller) {
controller.enqueue(chunk.toUpperCase());
},
flush(controller) {
// Pēc izvēles: Veiciet jebkādas pēdējās darbības, kad straume tiek aizvērta
},
});
Šajā piemērā transform()
metode pārveido datu gabalu par lielajiem burtiem un ievieto to kontroliera rindā. flush()
metode tiek izsaukta, kad straume tiek aizvērta, un to var izmantot, lai veiktu jebkādas pēdējās darbības.
TransformStreams izmantošana konveijeros
TransformStreams ir visnoderīgākās, ja tās tiek savienotas ķēdē, lai izveidotu datu apstrādes konveijerus. Jūs varat izmantot pipeThrough()
metodi, lai savienotu ReadableStream ar TransformStream un pēc tam ar WritableStream.
Šeit ir piemērs, kā izveidot konveijeru, kas lasa datus no ReadableStream, pārveido tos par lielajiem burtiem, izmantojot TransformStream, un pēc tam ieraksta tos WritableStream:
const readableStream = new ReadableStream({
start(controller) {
controller.enqueue('sveiki');
controller.enqueue('pasaule');
controller.close();
},
});
const transformStream = new TransformStream({
transform(chunk, controller) {
controller.enqueue(chunk.toUpperCase());
},
});
const writableStream = new WritableStream({
write(chunk) {
console.log('Raksta:', chunk);
return Promise.resolve();
},
});
readableStream.pipeThrough(transformStream).pipeTo(writableStream);
Šajā piemērā pipeThrough()
metode savieno readableStream
ar transformStream
, un pēc tam pipeTo()
metode savieno transformStream
ar writableStream
. Dati plūst no ReadableStream, caur TransformStream (kur tie tiek pārveidoti par lielajiem burtiem) un pēc tam uz WritableStream (kur tie tiek reģistrēti konsolē).
Pretspiediens
Pretspiediens ir būtisks mehānisms Web straumēs, kas neļauj ātrākam ražotājam pārslogot lēnāku patērētāju. Kad patērētājs nespēj sekot līdzi datu ražošanas ātrumam, tas var signalizēt ražotājam palēnināt darbību. Tas tiek panākts, izmantojot straumes kontrolieri un lasītāja/rakstītāja objektus.
Kad ReadableStream iekšējā rinda ir pilna, pull()
metode netiks izsaukta, kamēr rindā nebūs brīvas vietas. Līdzīgi WritableStream write()
metode var atgriezt solījumu, kas tiek atrisināts tikai tad, kad straume ir gatava pieņemt vairāk datu.
Pareizi apstrādājot pretspiedienu, jūs varat nodrošināt, ka jūsu datu apstrādes konveijeri ir robusti un efektīvi, pat strādājot ar mainīgiem datu pārraides ātrumiem.
Lietošanas gadījumi un piemēri
1. Lielu failu apstrāde
Web Streams API ir ideāli piemērots lielu failu apstrādei, neielādējot tos pilnībā atmiņā. Jūs varat lasīt failu pa daļām, apstrādāt katru daļu un rakstīt rezultātus citā failā vai straumē.
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) {
// Piemērs: Pārveido katru rindu par lielajiem burtiem
const lines = chunk.split('\n');
lines.forEach(line => controller.enqueue(line.toUpperCase() + '\n'));
}
});
await readableStream.pipeThrough(transformStream).pipeTo(writableStream);
console.log('Faila apstrāde pabeigta!');
}
// Lietošanas piemērs (nepieciešams Node.js)
// const fs = require('fs');
// processFile('input.txt', 'output.txt');
2. Tīkla pieprasījumu apstrāde
Jūs varat izmantot Web Streams API, lai apstrādātu datus, kas saņemti no tīkla pieprasījumiem, piemēram, API atbildes vai servera sūtītos notikumus (server-sent events). Tas ļauj sākt datu apstrādi, tiklīdz tie tiek saņemti, nevis gaidīt, kamēr tiks lejupielādēta visa atbilde.
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);
// Apstrādā saņemtos datus
console.log('Saņemts:', text);
}
} catch (error) {
console.error('Kļūda, lasot no straumes:', error);
} finally {
reader.releaseLock();
}
}
// Lietošanas piemērs
// fetchAndProcessData('https://example.com/api/data');
3. Reāllaika datu plūsmas
Web straumes ir piemērotas arī reāllaika datu plūsmu, piemēram, akciju cenu vai sensoru rādījumu, apstrādei. Jūs varat savienot ReadableStream ar datu avotu un apstrādāt ienākošos datus, tiklīdz tie tiek saņemti.
// Piemērs: Reāllaika datu plūsmas simulācija
const readableStream = new ReadableStream({
start(controller) {
let intervalId = setInterval(() => {
const data = Math.random(); // Simulē sensora nolasījumu
controller.enqueue(`Dati: ${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('Straume aizvērta.');
break;
}
console.log('Saņemts:', value);
}
} catch (error) {
console.error('Kļūda, lasot no straumes:', error);
} finally {
reader.releaseLock();
}
}
readStream();
// Apturēt straumi pēc 10 sekundēm
setTimeout(() => {readableStream.cancel()}, 10000);
Web Streams API lietošanas priekšrocības
- Uzlabota veiktspēja: Apstrādājiet datus pakāpeniski, samazinot atmiņas patēriņu un uzlabojot atsaucību.
- Uzlabota atmiņas pārvaldība: Izvairieties no veselu datu kopu ielādes atmiņā, kas ir īpaši noderīgi lieliem failiem vai tīkla straumēm.
- Labāka lietotāja pieredze: Sāciet apstrādāt un attēlot datus ātrāk, nodrošinot interaktīvāku un atsaucīgāku lietotāja pieredzi.
- Vienkāršota datu apstrāde: Izveidojiet modulārus un atkārtoti lietojamus datu apstrādes konveijerus, izmantojot TransformStreams.
- Pretspiediena atbalsts: Apstrādājiet mainīgus datu pārraides ātrumus un nepieļaujiet patērētāju pārslodzi.
Apsvērumi un labākā prakse
- Kļūdu apstrāde: Ieviesiet robustu kļūdu apstrādi, lai korekti apstrādātu straumes kļūdas un novērstu neparedzētu lietojumprogrammas uzvedību.
- Resursu pārvaldība: Pareizi atbrīvojiet resursus, kad straumes vairs nav nepieciešamas, lai izvairītos no atmiņas noplūdes. Izmantojiet
reader.releaseLock()
un nodrošiniet, ka straumes tiek attiecīgi aizvērtas vai pārtrauktas. - Kodēšana un dekodēšana: Izmantojiet
TextEncoderStream
unTextDecoderStream
teksta datu apstrādei, lai nodrošinātu pareizu rakstzīmju kodējumu. - Pārlūkprogrammu saderība: Pārbaudiet pārlūkprogrammu saderību pirms Web Streams API izmantošanas un apsveriet iespēju izmantot polifilus (polyfills) vecākām pārlūkprogrammām.
- Testēšana: Rūpīgi testējiet savus datu apstrādes konveijerus, lai nodrošinātu to pareizu darbību dažādos apstākļos.
Noslēgums
Web Streams API nodrošina jaudīgu un efektīvu veidu, kā apstrādāt straumētus datus JavaScript. Izprotot pamatjēdzienus un izmantojot dažādus straumju veidus, jūs varat izveidot robustas un atsaucīgas tīmekļa lietojumprogrammas, kas viegli apstrādā lielus failus, tīkla pieprasījumus un reāllaika datu plūsmas. Pretspiediena ieviešana un labākās prakses ievērošana kļūdu apstrādē un resursu pārvaldībā nodrošinās, ka jūsu datu apstrādes konveijeri ir uzticami un veiktspējīgi. Tā kā tīmekļa lietojumprogrammas turpina attīstīties un apstrādāt arvien sarežģītākus datus, Web Streams API kļūs par neaizstājamu rīku izstrādātājiem visā pasaulē.