Avastage reaktiivset programmeerimist JavaScriptis, kasutades RxJS-i. Õppige Observable vooge, mustreid ja praktilisi rakendusi responsiivsete ja skaleeritavate rakenduste loomiseks.
JavaScripti reaktiivne programmeerimine: RxJS mustrid ja Observable vood
Tänapäeva pidevalt arenevas veebiarenduse maastikul on responsiivsete, skaleeritavate ja hooldatavate rakenduste loomine esmatähtis. Reaktiivne programmeerimine (RP) pakub võimsat paradigmat asünkroonsete andmevoogude käsitlemiseks ja muudatuste levitamiseks kogu rakenduses. JavaScriptis RP rakendamiseks mõeldud populaarsete teekide seas paistab RxJS (Reactive Extensions for JavaScript) silma kui vastupidav ja mitmekülgne tööriist.
Mis on reaktiivne programmeerimine?
Oma olemuselt on reaktiivne programmeerimine seotud asünkroonsete andmevoogude ja muutuste levikuga. Kujutage ette arvutustabelit, kus ühe lahtri uuendamine arvutab automaatselt ümber seotud valemid. See ongi RP olemus – reageerimine andmete muutustele deklaratiivsel ja tõhusal viisil.
Traditsiooniline imperatiivne programmeerimine hõlmab sageli oleku haldamist ja komponentide käsitsi uuendamist vastusena sündmustele. See võib viia keeruka ja vigaderohke koodini, eriti asünkroonsete operatsioonide, nagu võrgupäringute või kasutaja interaktsioonide puhul. RP lihtsustab seda, käsitledes kõike andmevoona ja pakkudes operaatoreid nende voogude teisendamiseks, filtreerimiseks ja kombineerimiseks.
Sissejuhatus RxJS-i: Reaktiivsed laiendused JavaScriptile
RxJS on teek asünkroonsete ja sündmustepõhiste programmide koostamiseks, kasutades jälgitavaid (observable) järjestusi. See pakub võimsate operaatorite komplekti, mis võimaldavad teil andmevoogusid hõlpsalt manipuleerida. RxJS tugineb Vaatleja (Observer) mustrile, Iteraatori (Iterator) mustrile ja funktsionaalse programmeerimise kontseptsioonidele, et hallata sündmuste või andmete järjestusi tõhusalt.
RxJS-i põhimõisted:
- Observables (Jälgitavad): Esindavad andmevoogu, mida saab jälgida üks või mitu Vaatlejat (Observer). Need on laisad ja hakkavad väärtusi väljastama alles siis, kui neid on tellitud.
- Observers (Vaatlejad): Tarbivad Observables'i poolt väljastatud andmeid. Neil on kolm meetodit:
next()
väärtuste vastuvõtmiseks,error()
vigade käsitlemiseks jacomplete()
voo lõppemisest teatamiseks. - Operators (Operaatorid): Funktsioonid, mis teisendavad, filtreerivad, kombineerivad või manipuleerivad Observables'eid. RxJS pakub laia valikut operaatoreid erinevatel eesmärkidel.
- Subjects (Subjektid): Toimivad nii Observables'i kui ka Observer'itena, võimaldades andmeid edastada mitmele tellijale (multicast) ja samuti andmeid voogu lükata.
- Schedulers (Planeerijad): Kontrollivad Observables'i samaaegsust, võimaldades koodi käivitada sünkroonselt või asünkroonselt, erinevates lõimedes või kindlate viivitustega.
Observable vood ĂĽksikasjalikult
Observables on RxJS-i alus. Need esindavad andmevoogu, mida saab aja jooksul jälgida. Observable väljastab väärtusi oma tellijatele, kes saavad seejärel neid väärtusi töödelda või neile reageerida. Mõelge sellest kui torujuhtmest, kus andmed voolavad allikast ühe või mitme tarbijani.
Observable'ite loomine:
RxJS pakub mitmeid viise Observable'ite loomiseks:
Observable.create()
: Madala taseme meetod, mis annab teile täieliku kontrolli Observable'i käitumise üle.from()
: Teisendab massiivi, lubaduse (promise), itereeritava või Observable-laadse objekti Observable'iks.of()
: Loob Observable'i, mis väljastab väärtuste jada.interval()
: Loob Observable'i, mis väljastab numbrite jada kindlaksmääratud intervalliga.timer()
: Loob Observable'i, mis väljastab ühe väärtuse pärast määratud viivitust või väljastab numbrite jada kindla intervalliga pärast viivitust.fromEvent()
: Loob Observable'i, mis väljastab sündmusi DOM-elemendist või muust sündmusallikast.
Näide: Observable'i loomine massiivist
```javascript import { from } from 'rxjs'; const myArray = [1, 2, 3, 4, 5]; const myObservable = from(myArray); myObservable.subscribe( value => console.log('Saadud:', value), error => console.error('Viga:', error), () => console.log('Lõpetatud') ); // Väljund: // Saadud: 1 // Saadud: 2 // Saadud: 3 // Saadud: 4 // Saadud: 5 // Lõpetatud ```
Näide: Observable'i loomine sündmusest
```javascript import { fromEvent } from 'rxjs'; const button = document.getElementById('myButton'); const clickObservable = fromEvent(button, 'click'); clickObservable.subscribe( event => console.log('Nupule klõpsati!', event) ); ```
Observable'ite tellimine:
Observable'ilt väärtuste saamise alustamiseks peate selle tellima meetodiga subscribe()
. Meetod subscribe()
aktsepteerib kuni kolme argumenti:
next
: Funktsioon, mis kutsutakse välja iga Observable'i poolt väljastatud väärtuse puhul.error
: Funktsioon, mis kutsutakse välja, kui Observable väljastab vea.complete
: Funktsioon, mis kutsutakse välja, kui Observable lõpetab (annab märku voo lõpust).
Meetod subscribe()
tagastab Subscription objekti, mis esindab ühendust Observable'i ja Observer'i vahel. Saate kasutada Subscription objekti, et Observable'ist lahti tellida, vältides edasiste väärtuste väljastamist.
Observable'itest lahti tellimine:
Lahti tellimine on oluline mälulekete vältimiseks, eriti pikaealiste või sageli väärtusi väljastavate Observable'itega tegelemisel. Saate Observable'ist lahti tellida, kutsudes Subscription objektil välja meetodi unsubscribe()
.
```javascript import { interval } from 'rxjs'; const myInterval = interval(1000); const subscription = myInterval.subscribe( value => console.log('Intervall:', value) ); // 5 sekundi pärast, tühista tellimus setTimeout(() => { subscription.unsubscribe(); console.log('Tellimus tühistatud!'); }, 5000); // Väljund (ligikaudne): // Intervall: 0 // Intervall: 1 // Intervall: 2 // Intervall: 3 // Intervall: 4 // Tellimus tühistatud! ```
RxJS operaatorid: Andmevoogude teisendamine ja filtreerimine
RxJS operaatorid on teegi süda. Need võimaldavad teil teisendada, filtreerida, kombineerida ja manipuleerida Observables'eid deklaratiivsel ja komponeeritaval viisil. Saadaval on arvukalt operaatoreid, millest igaüks täidab kindlat eesmärki. Siin on mõned kõige sagedamini kasutatavad operaatorid:
Teisendusoperaatorid:
map()
: Rakendab funktsiooni igale Observable'i poolt väljastatud väärtusele ja väljastab tulemuse. Sarnanemap()
meetodile massiivides.pluck()
: Eraldab kindla omaduse igast Observable'i poolt väljastatud väärtusest.scan()
: Rakendab akumulaatorfunktsiooni lähte-Observable'i peal ja tagastab iga vahetulemuse.buffer()
: Kogub väärtused lähte-Observable'ist massiivi ja väljastab massiivi, kui konkreetne tingimus on täidetud.window()
: Sarnanebuffer()
'ile, kuid massiivi asemel väljastab see Observable'i, mis esindab väärtuste akent.
Näide: map()
operaatori kasutamine
```javascript import { from } from 'rxjs'; import { map } from 'rxjs/operators'; const numbers = from([1, 2, 3, 4, 5]); const squaredNumbers = numbers.pipe( map(x => x * x) ); squaredNumbers.subscribe(value => console.log('Ruudus:', value)); // Väljund: // Ruudus: 1 // Ruudus: 4 // Ruudus: 9 // Ruudus: 16 // Ruudus: 25 ```
Filtreerimisoperaatorid:
filter()
: Väljastab ainult väärtused, mis vastavad kindlale tingimusele.debounceTime()
: Viivitab väärtuste väljastamist, kuni on möödunud teatud aeg ilma uute väärtuste väljastamiseta. Kasulik kasutajasisendi käsitlemiseks ja liigsete päringute vältimiseks.distinctUntilChanged()
: Väljastab ainult väärtused, mis erinevad eelmisest väärtusest.take()
: Väljastab ainult esimesed N väärtust Observable'ist.skip()
: Jätab vahele esimesed N väärtust Observable'ist ja väljastab ülejäänud väärtused.
Näide: filter()
operaatori kasutamine
```javascript import { from } from 'rxjs'; import { filter } from 'rxjs/operators'; const numbers = from([1, 2, 3, 4, 5, 6]); const evenNumbers = numbers.pipe( filter(x => x % 2 === 0) ); evenNumbers.subscribe(value => console.log('Paarisarv:', value)); // Väljund: // Paarisarv: 2 // Paarisarv: 4 // Paarisarv: 6 ```
Kombineerimisoperaatorid:
merge()
: Ăśhendab mitu Observable'it ĂĽheks Observable'iks.concat()
: Aheldab mitu Observable'it, väljastades väärtusi igast Observable'ist järjestikku.combineLatest()
: Kombineerib viimased väärtused mitmest Observable'ist ja väljastab uue väärtuse alati, kui mõni lähte-Observable väljastab väärtuse.zip()
: Kombineerib väärtused mitmest Observable'ist nende indeksi alusel ja väljastab uue väärtuse iga kombinatsiooni kohta.withLatestFrom()
: Kombineerib viimase väärtuse teisest Observable'ist lähte-Observable'i praeguse väärtusega.
Näide: combineLatest()
operaatori kasutamine
```javascript import { interval, combineLatest } from 'rxjs'; import { map } from 'rxjs/operators'; const interval1 = interval(1000); const interval2 = interval(2000); const combinedIntervals = combineLatest( interval1, interval2, (x, y) => `Intervall 1: ${x}, Intervall 2: ${y}` ); combinedIntervals.subscribe(value => console.log(value)); // Väljund (ligikaudne): // Intervall 1: 0, Intervall 2: 0 // Intervall 1: 1, Intervall 2: 0 // Intervall 1: 1, Intervall 2: 1 // Intervall 1: 2, Intervall 2: 1 // Intervall 1: 2, Intervall 2: 2 // ... ```
Levinud RxJS mustrid
RxJS pakub mitmeid võimsaid mustreid, mis võivad lihtsustada levinud asünkroonseid programmeerimisülesandeid:
Debouncing (Väreluse eemaldamine):
Operaatorit debounceTime()
kasutatakse väärtuste väljastamise viivitamiseks, kuni on möödunud teatud aeg ilma uute väärtuste väljastamiseta. See on eriti kasulik kasutajasisendi käsitlemiseks, näiteks otsingupäringute või vormide esitamise puhul, kus soovite vältida liigseid päringuid serverile.
Näide: Otsingusisendi väreluse eemaldamine
```javascript import { fromEvent } from 'rxjs'; import { map, debounceTime, distinctUntilChanged } from 'rxjs/operators'; const searchInput = document.getElementById('searchInput'); const searchObservable = fromEvent(searchInput, 'keyup').pipe( map((event: any) => event.target.value), debounceTime(300), // Oota 300ms pärast igat klahvivajutust distinctUntilChanged() // Väljasta ainult siis, kui väärtus on muutunud ); searchObservable.subscribe(searchTerm => { console.log('Otsin:', searchTerm); // Tee API-päring termini otsimiseks }); ```
Throttling (Läbilaske piiramine):
Operaator throttleTime()
piirab kiirust, millega väärtusi Observable'ist väljastatakse. See väljastab esimese väärtuse, mis väljastatakse kindlaksmääratud ajaakna jooksul, ja ignoreerib järgnevaid väärtusi, kuni aken sulgub. See on kasulik sündmuste sageduse piiramiseks, näiteks kerimis- või suuruse muutmise sündmuste puhul.
Switching (Vahetamine):
Operaatorit switchMap()
kasutatakse uuele Observable'ile ümberlülitumiseks alati, kui lähte-Observable'ist väljastatakse uus väärtus. See on kasulik ootel olevate päringute tühistamiseks, kui algatatakse uus päring. Näiteks saate kasutada switchMap()
'i eelmise otsingupäringu tühistamiseks, kui kasutaja sisestab otsingusisendisse uue tähe.
Näide: switchMap()
kasutamine ennetava otsingu jaoks
```javascript import { fromEvent, of } from 'rxjs'; import { map, debounceTime, distinctUntilChanged, switchMap, catchError } from 'rxjs/operators'; const searchInput = document.getElementById('searchInput'); const searchObservable = fromEvent(searchInput, 'keyup').pipe( map((event: any) => event.target.value), debounceTime(300), distinctUntilChanged(), switchMap(searchTerm => { // Tee API-päring termini otsimiseks return searchAPI(searchTerm).pipe( catchError(error => { console.error('Otsimisel tekkis viga:', error); return of([]); // Vea korral tagasta tühi massiiv }) ); }) ); searchObservable.subscribe(results => { console.log('Otsingutulemused:', results); // Uuenda kasutajaliidest otsingutulemustega }); function searchAPI(searchTerm: string) { // Simuleeri API-päringut return of([`Tulemus päringule ${searchTerm} 1`, `Tulemus päringule ${searchTerm} 2`]); } ```
RxJS-i praktilised rakendused
RxJS on mitmekülgne teek, mida saab kasutada laias valikus rakendustes. Siin on mõned levinud kasutusjuhud:
- Kasutajasisendi käsitlemine: RxJS-i saab kasutada kasutajasisendi sündmuste, näiteks klahvivajutuste, hiireklõpsude ja vormide esitamise käsitlemiseks. Operaatoreid nagu
debounceTime()
jathrottleTime()
saab kasutada jõudluse optimeerimiseks ja liigsete päringute vältimiseks. - Asünkroonsete operatsioonide haldamine: RxJS pakub võimsat viisi asünkroonsete operatsioonide, näiteks võrgupäringute ja taimerite haldamiseks. Operaatoreid nagu
switchMap()
jamergeMap()
saab kasutada samaaegsete päringute käsitlemiseks ja ootel olevate päringute tühistamiseks. - Reaalajas rakenduste loomine: RxJS sobib hästi reaalajas rakenduste, näiteks vestlusrakenduste ja armatuurlaudade loomiseks. Observables'eid saab kasutada andmevoogude esitamiseks WebSocketidest või Server-Sent Events (SSE) kaudu.
- Oleku haldamine: RxJS-i saab kasutada olekuhalduslahendusena raamistikes nagu Angular, React ja Vue.js. Observables'eid saab kasutada rakenduse oleku esitamiseks ning operaatoreid oleku teisendamiseks ja uuendamiseks vastusena kasutaja tegevustele või sündmustele.
RxJS koos populaarsete raamistikega
Angular:
Angular tugineb tugevalt RxJS-ile asünkroonsete operatsioonide käsitlemisel ja andmevoogude haldamisel. Angulari HttpClient
teenus tagastab Observables'eid ning RxJS operaatoreid kasutatakse laialdaselt API-päringutest tagastatud andmete teisendamiseks ja filtreerimiseks. Angulari muudatuste tuvastamise mehhanism kasutab samuti RxJS-i, et kasutajaliidest tõhusalt uuendada vastusena andmete muutustele.
Näide: RxJS kasutamine Angulari HttpClientiga
```typescript
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class DataService {
private apiUrl = 'https://api.example.com/data';
constructor(private http: HttpClient) { }
getData(): Observable
React:
Kuigi Reactil ei ole sisseehitatud RxJS-i tuge, saab seda hõlpsasti integreerida, kasutades teeke nagu rxjs-hooks
või use-rx
. Need teegid pakuvad kohandatud Hooke, mis võimaldavad teil tellida Observables'eid ja hallata tellimusi Reacti komponentides. RxJS-i saab Reactis kasutada asünkroonseks andmete hankimiseks, komponendi oleku haldamiseks ja reaktiivsete kasutajaliideste loomiseks.
Näide: RxJS kasutamine Reacti Hookidega
```javascript import React, { useState, useEffect } from 'react'; import { Subject } from 'rxjs'; import { scan } from 'rxjs/operators'; function Counter() { const [count, setCount] = useState(0); const increment$ = new Subject(); useEffect(() => { const subscription = increment$.pipe( scan(acc => acc + 1, 0) ).subscribe(setCount); return () => subscription.unsubscribe(); }, []); return (
Arv: {count}
Vue.js:
Ka Vue.js-il pole natiivset RxJS-i integratsiooni, kuid seda saab kasutada teekidega nagu vue-rx
või hallates tellimusi käsitsi Vue komponentides. RxJS-i saab Vue.js-is kasutada sarnastel eesmärkidel nagu Reactis, näiteks asünkroonseks andmete hankimiseks ja komponendi oleku haldamiseks.
RxJS-i kasutamise parimad praktikad
- Tühistage Observable'ite tellimus: Tühistage alati Observable'ite tellimus, kui neid enam ei vajata, et vältida mälulekkeid. Kasutage tellimuse tühistamiseks meetodi
subscribe()
poolt tagastatud Subscription objekti. - Kasutage
pipe()
meetodit: Kasutage meetoditpipe()
operaatorite aheldamiseks loetaval ja hooldataval viisil. - Käsitsege vigu sujuvalt: Kasutage operaatorit
catchError()
vigade käsitlemiseks ja nende levimise vältimiseks Observable'i ahelas. - Valige õiged operaatorid: Valige oma konkreetse kasutusjuhtumi jaoks sobivad operaatorid. RxJS pakub laia valikut operaatoreid, seega on oluline mõista nende eesmärki ja käitumist.
- Hoidke Observable'id lihtsad: Vältige liiga keerukate Observable'ite loomist. Jagage keerulised operatsioonid väiksemateks, paremini hallatavateks Observable'iteks.
RxJS-i edasijõudnute kontseptsioonid
Subjects (Subjektid):
Subjektid toimivad nii Observables'i kui ka Observer'itena. Need võimaldavad teil andmeid edastada mitmele tellijale (multicast) ja samuti andmeid voogu lükata. On olemas erinevat tüüpi Subjekte, sealhulgas:
- Subject: Põhiline Subjekt, mis edastab väärtusi kõigile tellijatele.
- BehaviorSubject: Nõuab algväärtust ja väljastab praeguse väärtuse uutele tellijatele.
- ReplaySubject: Puhverdab kindlaksmääratud arvu väärtusi ja esitab need uuesti uutele tellijatele.
- AsyncSubject: Väljastab ainult viimase väärtuse, kui Observable lõpetab.
Schedulers (Planeerijad):
Planeerijad kontrollivad Observables'i samaaegsust. Need võimaldavad teil koodi käivitada sünkroonselt või asünkroonselt, erinevates lõimedes või kindlate viivitustega. RxJS pakub mitmeid sisseehitatud planeerijaid, sealhulgas:
queueScheduler
: Planeerib ülesanded täitmiseks praeguses JavaScripti lõimes, pärast praegust täitmiskonteksti.asapScheduler
: Planeerib ülesanded täitmiseks praeguses JavaScripti lõimes, niipea kui võimalik pärast praegust täitmiskonteksti.asyncScheduler
: Planeerib ülesanded asünkroonseks täitmiseks, kasutadessetTimeout
võisetInterval
.animationFrameScheduler
: Planeerib ülesanded täitmiseks järgmisel animatsioonikaadril.
Kokkuvõte
RxJS on võimas teek reaktiivsete rakenduste loomiseks JavaScriptis. Omandades Observables'id, operaatorid ja levinud mustrid, saate luua responsiivsemaid, skaleeritavamaid ja hooldatavamaid rakendusi. Olenemata sellest, kas töötate Angulari, Reacti, Vue.js-i või puhta JavaScriptiga, võib RxJS oluliselt parandada teie võimet käsitleda asünkroonseid andmevooge ja ehitada keerukaid kasutajaliideseid.
Võtke omaks reaktiivse programmeerimise jõud RxJS-iga ja avage uued võimalused oma JavaScripti rakenduste jaoks!