Përshëndetje të gjithëve. Këtu është Omelnytskiy Serhiy. Para pak kohe mbajta një transmetim për programimin reaktiv, ku flas për asinkronitetin në JavaScript. Sot do doja të përmbledh këtë material.

Por para se të fillojmë me materialin kryesor, na nevojitet një hyrje. Le të fillojmë me definita: çfarë është staku dhe radhitja?
Staku â Ă«shtĂ« njĂ« koleksion, elementet e tĂ« cilit merret sipas parimit "i fundit i hyrĂ«, i pari i dalĂ«" LIFO
Radhitja â Ă«shtĂ« njĂ« koleksion, elementet e tĂ« cilit merret sipas parimit "i pari i hyrĂ«, i pari i dalĂ«" FIFO
Mirë, të vazhdojmë.

JavaScript është një gjuhë programimi njëpërmasore. Kjo do të thotë se ka vetëm një rrjedhë ekzekutimi dhe një stok, në të cilin vendosen funksionet në radhë për ekzekutim. Si pasojë, në një moment të vetëm JavaScript mund të ekzekutojë vetëm një operacion, operacione të tjera do të presin në radhë derisa të thirren.
Staku i thirrjeve â Ă«shtĂ« njĂ« strukturĂ« tĂ« dhĂ«nash qĂ«, nĂ« terma tĂ« thjeshtĂ«, regjistron informacionin mbi vendin nĂ« program ku ndodhemi. NĂ«se kalojmĂ« nĂ« njĂ« funksion, ne vendosim njĂ« regjistrim pĂ«r tĂ« nĂ« majĂ« tĂ« stack-ut. Kur kthehemi nga funksioni, ne nxjerrim elementin mĂ« tĂ« lartĂ« nga stack-u dhe pĂ«rfundojmĂ« atje ku e kemi thirrur kĂ«tĂ« funksion. Kjo Ă«shtĂ« e gjitha qĂ« mund tĂ« bĂ«jĂ« stack-u. Tani njĂ« pyetje mjaft interesante. Si funksionon atĂ«herĂ« asinkroniciteti nĂ« JavaScript?

Në të vërtetë, përveç stack-ut, në shfletues ka një radhë të veçantë për të punuar me atë që quhet WebAPI. Funksionet nga kjo radhë do të ekzekutohen në rendësi vetëm pasi stack-u të jetë plotësisht i zbrazët. Vetëm pas kësaj ato vendosen nga radhë në stack për t'u ekzekutuar. Nëse në stack aktualisht ndodhet të paktën një element, ato nuk mund të hyjnë në stack. Pikërisht për këtë arsye thirrjet e funksioneve me timeout shpesh nuk janë të sakta në kohë, sepse funksioni nuk mund të hyjë nga radhë në stack derisa ai të jetë i plotë.
Le të shqyrtojmë shembullin e mëposhtëm dhe të merremi me "ekzekutimin" e tij hap pas hapi. Po ashtu, do të shikojmë se çfarë ndodh në sistem gjatë kësaj procedure.
console.log('Hi);
setTimeout(function cb1() {
console.log('cb1');
}, 5000);
console.log('Bye');
1) Deri asnjë gjë. Konsola e shfletuesit është e pastër, staku i thirrjeve është i zbrazët.

2) MĂ« pas, komanda console.log(âHiâ) shtohet nĂ« stakun e thirrjeve.

3) Dhe ajo ekzekutohet.

4) Pjesa console.log(âHiâ) hiqet nga staku i thirrjeve.

5) Tani kalojmë te komanda setTimeout(function cb1() {⊠}). Ajo shtohet në stakun e thirrjeve.

6) Komanda setTimeout(function cb1() {⊠}) ekzekutohet. Shfletuesi krijon një timer që është pjesë e Web API. Ai do të bëjë numërimin mbrapsht.

7) Komanda setTimeout(function cb1() {⊠}) përfundon dhe hiqet nga staku i thirrjeve.

8) Komanda console.log(âByeâ) shtohet nĂ« stakun e thirrjeve.

9) Komanda console.log(âByeâ) ekzekutohet.

10) Komanda console.log(âByeâ) hiqet nga staku i thirrjeve.

11) Pasi të kalojnë, të paktën, 5000 ms., timer-i përfundojnë dhe vendos kolb-bekimin cb1 në radhën e kolb-bekimeve.

12) Cikli i ngjarjeve merr funksionin cb1 nga radhë e kolb-bekimeve dhe e vendos atë në stakun e thirrjeve.

13) Funksioni cb1 ekzekutohet dhe shton console.log(âcb1â) nĂ« stakun e thirrjeve.

14) Komanda console.log(âcb1â) ekzekutohet.

15) Komanda console.log(âcb1â) hiqet nga staku i thirrjeve.

16) Funksioni cb1 hiqet nga staku i thirrjeve.
Shikojmë një shembull në dinamikë:

Tani që kemi shqyrtuar se si është implementuar asinkronia në JavaScript, le të flasim shkurtimisht mbi evolucionin e kodit asinkron.
Evolucioni i kodit asinkron.
a(function (resultsFromA) {
b(resultsFromA, function (resultsFromB) {
c(resultsFromB, function (resultsFromC) {
d(resultsFromC, function (resultsFromD) {
e(resultsFromD, function (resultsFromE) {
f(resultsFromE, function (resultsFromF) {
console.log(resultsFromF);
})
})
})
})
})
});Programimi asinkron, siç e dimë ne JavaScript, mund të implementohet vetëm me funksione. Ato mund të kalohen si çdo variabël tjetër në funksione të tjera. Kështu lindën callback-ët. Dhe kjo është argëtuese dhe gëzuese derisa të shndërrohet në trishtim, mërzi dhe brengë. Pse? Sepse është shumë e thjeshtë:
- Me rritjen e kompleksitetit të kodit, projekti shpejt shndërrohet në blloqe të thelluara të paqartë - "callback hell".
- Përpunimi i gabimeve lehtësisht mund të humbasë.
- Nuk është e mundur të kthehen shprehje me return.
Me ardhjen e Promise, situata u bë pak më e mirë.
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 2000);
}).then((result) => {
alert(result);
return result + 2;
}).then((result) => {
throw new Error('FAILED HERE');
alert(result);
return result + 2;
}).then((result) => {
alert(result);
return result + 2;
}).catch((e) => {
console.log('error: ', e);
});- Me shfaqen zinxhirë promisesh, që e përmirësojnë lexueshmërinë e kodit
- Shfaqet një metodë e veçantë për kapjen e gabimeve
- Shfaqet mundësia e ekzekutimit paralel me ndihmën e Promise.all
- Asinhronësinë e brendshme mund ta zgjidhim me async/await
Por promesa ka kufizimet e saj. PĂ«r shembull, njĂ« promise, pa ndonjĂ« marrĂ«veshje tĂ« veçantĂ«, nuk mund tĂ« anulohet, dhe mĂ« e rĂ«ndĂ«sishmja â punon vetĂ«m me njĂ« vlerĂ«.
Tani ne kemi arritur smooth në programimin reaktiv. A jeni të lodhur? Mirë, mund të shkoni të bëni një çaj, të mendoni dhe të ktheheni për të lexuar më tej. Unë do të vazhdoj.

Programimi reaktivââânjĂ« paradigme programimi qĂ« Ă«shtĂ« e orientuar nga rrjedhat e tĂ« dhĂ«nave dhe shpĂ«rndarjen e ndryshimeve. Le tĂ« shqyrtojmĂ« mĂ« nĂ« detaje se çfarĂ« Ă«shtĂ« rrjedha e tĂ« dhĂ«nave.
// ĐĐŸĐ»ŃŃĐ°Đ”ĐŒ ŃŃŃĐ»ĐșŃ ĐœĐ° ŃĐ»Đ”ĐŒĐ”ĐœŃ
const input = ducument.querySelector('input');
const eventsArray = [];
// ĐŃŃĐžĐŒ ĐșĐ°Đ¶ĐŽĐŸĐ” ŃĐŸĐ±ŃŃОД ĐČ ĐŒĐ°ŃŃĐžĐČ eventsArray
input.addEventListener('keyup',
event => eventsArray.push(event)
);Imagjinoni se kemi një fushë hyrëse. Ne krijojmë një masiv dhe për çdo ngjarje keyup të inputit do të ruajmë ngjarjen në masivin tonë. Dëshirojmë të theksojmë se masivi ynë është renditur sipas kohës, pra indeksi i ngjarjeve më të vona është më i madh se indeksi i atyre më të hershme. Ky masiv përfaqëson një model të thjeshtuar të rrjedhjes së të dhënave, por nuk është ende një rrjedhë. Për ta quajtur këtë masiv me siguri një rrjedhë, ai duhet të dijë se si t'i informojë abonuesit për të dhënat e reja që janë marrë. Kështu arritëm në përcaktimin e rrjedhës.
Shkalla e të dhënave
const { interval1 } = Rx;
const { take } = RxOperators;
interval(1000).pipe(
take(4)
)
Rrjedhaështë një masiv të dhënash të renditura sipas kohës, i cili mund t'i njoftojë se të dhënat kanë ndryshuar. Tani imagjinoni sa e lehtë është të shkruani kod, ku për një veprim duhet të thërrisni disa ngjarje në pjesë të ndryshme të kodit. Ne thjesht bëjmë një abonim në rrjedhë dhe ajo na informon vetë kur ndodhin ndryshimet. Këtë e bën biblioteka RxJs.

RxJS â Ă«shtĂ« njĂ« bibliotekĂ« pĂ«r tĂ« punuar me programe asinkrone dhe tĂ« bazuara nĂ« ngjarje duke pĂ«rdorur sekuenca tĂ« vĂ«zhguara. Biblioteca ofron tipin kryesor Observable, disa lloje ndihmĂ«se (Observer, Schedulers, Subjects) dhe operatorĂ« pĂ«r tĂ« punuar me ngjarjet si me koleksionet (map, filter, reduce, every dhe tĂ« ngjashme nga JavaScript Array).
Le të shqyrtojmë konceptet kryesore të kësaj biblioteke.
Observable, Observer, Producer
Observable është tipi i parë bazë që do të shqyrtojmë. Ky klas përmban pjesën kryesore të implementimit të RxJs. Ai është i lidhur me fluxin e vëzhguar, në të cilin mund të abonoheni përmes metodës subscribe.
Në Observable implementohet një mekanizëm ndihmës për krijimin e azhurnimeve, e ashtuquajtura Observer. Burimi i vlerave për Observer quhet Prodhues. Kjo mund të jetë një array, një iterues, web socket, një ngjarje etj. Pra, mund të thuhet se observable është një lidhës midis Producer dhe Observer.
Observable përpunon tri lloje ngjarjesh për Observer:
- next â tĂ« dhĂ«na tĂ« reja
- error â njĂ« gabim, nĂ«se sekuenca pĂ«rfundoi pĂ«r shkak tĂ« njĂ« situate pĂ«rjashtimi. Ky ngjarje gjithashtu presupozon pĂ«rfundimin e sekuencĂ«s.
- komplet - sinjali i përfundimit të sekuencës. Kjo do të thotë se nuk do të ketë më të dhëna të reja
Të shohim një demo:

Në fillim do të përpunojmë vlerat 1, 2, 3, dhe pas 1 sek. do të marrim 4 dhe do të përfundojmë stream-in tonë.
Të mendojmë në zë
Dhe kĂ«tu e kuptova se ishte mĂ« interesant tĂ« tregoja se sa tĂ« shkruaja pĂ«r kĂ«tĂ«. đ
Abonim
Kur ne bëjmë një abonim në stream, krijojmë një klasë të re subscription, e cila na jep mundësinë të anulojmë abonimin me metodën unsubscribe. Gjithashtu, mund të grumbullojmë abonimet me metodën shto. Dhe është logjike që mund të shkëpusim stream-et me remove. Metodat add dhe remove pranojnë një abonim të tjetër si argument. Dëshiroj të theksoj se kur ne bëjmë anullimin, ne anulojmë të gjitha abonimet fëmijë siç do të thoshim se ato do të thërrisnin metodën unsubscribe. Të vazhdojmë më tej.
Llojet e stream-eve
| Nxehtë | Ftohtë |
|---|---|
| Prodhuese krijohet jashtë observable | Prodhuese krijohet brenda observable |
| Të dhënat transmetohen në momentin e krijimit të observable | Të dhënat komunikohen në momentin e abonimit |
| Nevojitet logjikë shtesë për anulimin | Stream-i përfundon vetë |
| Përdor lidhjen një-në-shumë | Përdor lidhjen një-në-një |
| Të gjitha abonimet kanë një vlerë të vetme | Abonimet janë të pavarura |
| Të dhënat mund të humbasin nëse nuk ka subscription | Rindez të gjitha vlerat e rrjedhës për një abonim të ri |
NĂ«se do tĂ« bĂ«nim njĂ« krahasim, do ta pĂ«rshkruaja rrjedhĂ«n e ngrohtĂ« si njĂ« film nĂ« kinema. NĂ« momentin kur ke hyrĂ«, aty e ke filluar shikimin. RrjedhĂ«n e ftohtĂ« do ta krahasoja me njĂ« telefonatĂ« nĂ« mbĂ«shtetje teknike. Ădo person qĂ« telefonon do tĂ« dĂ«gjojĂ« regjistrimin e automatikĂ«s nga fillimi deri nĂ« fund, por ti mund tĂ« ndĂ«rpresĂ«sh telefonatĂ«n duke u unsubscribe.
DĂ«shiroj tĂ« theksoj se ekzistojnĂ« edhe rrjedha tĂ« ashtuquajtura tĂ« ngrohta (kĂ«tĂ« definicion e kam hasur jashtĂ«zakonisht rrallĂ« dhe vetĂ«m nĂ« komunitetet ndĂ«rkombĂ«tare) â kjo Ă«shtĂ« njĂ« rrjedhĂ« qĂ« transformohet nga e ftohtĂ« nĂ« tĂ« ngrohtĂ«. Lind pyetja â ku tĂ« pĂ«rdoret? Do tĂ« jap njĂ« shembull nga praktika.
Unë punoj me Angular. Ai përdor aktivisht rxjs. Për të marrë të dhëna nga serveri, unë pres një rrjedhë të ftohtë dhe këtë rrjedhë e përdor në shabllon përmes asyncPipe. Nëse e përdor këtë pipë disa herë, duke u kthyer te definicioni i rrjedhës së ftohtë, çdo pipë do të kërkojë të dhëna nga serveri, që është, për ta thënë butë, e çuditshme. Ndërsa nëse e konvertoj rrjedhën e ftohtë në një të ngrohtë, kërkesa do të ndodhë vetëm një herë.
Në të vërtetë, kuptimi i llojeve të rrjedhave është mjaft i komplikuar për fillestarët, por është i rëndësishëm.
Operators
return this.http.get(`${environment.apiUrl}/${this.apiUrl}/trade_companies`)
.pipe(
tap(({ data }: TradeCompanyList) => this.companies$$.next(cloneDeep(data))),
map(({ data }: TradeCompanyList) => data)
);Opertorët na ofrojnë mundësi të zgjeruara për të punuar me rrjedhat. Ata ndihmojnë në kontrollin e ngjarjeve që ndodhin në Observable. Do të shqyrtojmë disa nga më të njohurit, ndërsa për më shumë informacion rreth operatorëve mund të konsultoheni me lidhjet në informacionin e dobishëm.
Operators â of
Le të fillojmë me operatorin ndihmës of. Ai krijon një Observable në bazë të një vlerë të thjeshtë.

Operators â filter

Operatori i filtrimit filter, siç mund të kuptohet nga emri, filtrojnë sinjalin e rrjedhës. Nëse operatori kthen një vërtetësi, atëherë e kalon më tej.
OperatorĂ«t â merr

merr â Pranon vlerĂ«n e numrit tĂ« emetimeve pas tĂ« cilave mbyll rrjedhĂ«n.
OperatorĂ«t â debounceTime

debounceTime â eliminon vlerat e emetuara qĂ« bien brenda njĂ« periudhe kohe tĂ« caktuar midis tĂ« dhĂ«nave tĂ« daljes â pas kalimit tĂ« intervalit kohor emeton vlerĂ«n e fundit.
const { Observable } = Rx;
const { debounceTime, take } = RxOperators;
Observable.create((observer) => {
let i = 1;
observer.next(i++);
// Emeton vlerën çdo 1000ms
setInterval(() => {
observer.next(i++)
}, 1000);
// Emeton vlerën çdo 1500ms
setInterval(() => {
observer.next(i++)
}, 1500);
}).pipe(
debounceTime(700), // Prit 700ms pĂ«r vlerĂ«n para se taćŠie
take(3)
); 
OperatorĂ«t â takeWhile

Emeton vlera derisa takeWhile të kthejë false, pas së cilës do të çregjistrohet nga rrjedha.
const { Observable } = Rx;
const { debounceTime, takeWhile } = RxOperators;
Observable.create((observer) => {
let i = 1;
observer.next(i++);
// Emeton vlerën çdo 1000ms
setInterval(() => {
observer.next(i++)
}, 1000);
}).pipe(
takeWhile( prodhues => prodhues < 5 )
); 
OperatorĂ«t â combineLatest
Operatori i kombinuar combineLatest është disi i ngjashëm me promise.all. Ai bashkon disa rrjedha në një të vetëm. Pasi çdo rrjedhë të emitojë të paktën një herë, ne marrim vlerat e fundit nga çdo njëri si një array. Pas çdo emiti nga rrjedhat e kombinuara, ai do të kthejë vlera të reja.

const { combineLatest, Observable } = Rx;
const { take } = RxOperators;
const observer_1 = Observable.create((observer) => {
let i = 1;
// Emiton një vlerë çdo 1000ms
setInterval(() => {
observer.next('a: ' + i++);
}, 1000);
});
const observer_2 = Observable.create((observer) => {
let i = 1;
// Emiton një vlerë çdo 750ms
setInterval(() => {
observer.next('b: ' + i++);
}, 750);
});
combineLatest(observer_1, observer_2).pipe(take(5));
OperatorĂ«t â zip
Zip â pret njĂ« vlerĂ« nga secila rrjedhĂ« dhe formon njĂ« array nĂ« bazĂ« tĂ« kĂ«tyre vlerave. NĂ«se nuk vjen asnjĂ« vlerĂ« nga ndonjĂ« rrjedhĂ«, grupi nuk do tĂ« formohet.

const { zip, Observable } = Rx;
const { take } = RxOperators;
const observer_1 = Observable.create((observer) => {
let i = 1;
\/\/ Emitted value every 1000ms
setInterval(() => {
observer.next('a: ' + i++);
}, 1000);
});
const observer_2 = Observable.create((observer) => {
let i = 1;
\/\/ Emitted value every 750
setInterval(() => {
observer.next('b: ' + i++);
}, 750);
});
const observer_3 = Observable.create((observer) => {
let i = 1;
\/\/ Emitted value every 500
setInterval(() => {
observer.next('c: ' + i++);
}, 500);
});
zip(observer_1, observer_2, observer_3).pipe(take(5));
Operators â forkJoin
forkJoin gjithashtu bashkon rrjedhat, por ai e lëshon vlerën vetëm kur të gjitha rrjedhat të përfundojnë (complete).

const { forkJoin, Observable } = Rx;
const { take } = RxOperators;
const observer_1 = Observable.create((observer) => {
let i = 1;
\/\/ Emitted value every 1000ms
setInterval(() => {
observer.next('a: ' + i++);
}, 1000);
}).pipe(take(3));
const observer_2 = Observable.create((observer) => {
let i = 1;
\/\/ Emitted value every 750
setInterval(() => {
observer.next('b: ' + i++);
}, 750);
}).pipe(take(5));
const observer_3 = Observable.create((observer) => {
let i = 1;
\/\/ Emitted value every 500
setInterval(() => {
observer.next('c: ' + i++);
}, 500);
}).pipe(take(4));
forkJoin(observer_1, observer_2, observer_3);
Operators â map
Operatori i transformimit map e ndryshon vlerën e emetimit në një të re.

const { Observable } = Rx;
const { take, map } = RxOperators;
Observable.create((observer) => {
let i = 1;
// ĂlirojnĂ« vlerĂ«n çdo 1000ms
setInterval(() => {
observer.next(i++);
}, 1000);
}).pipe(
map(x => x * 10),
take(3)
);

OperatorĂ«t â share, tap
Operatori tap lejon të bëhen efekte anësore, domethënë ndonjë veprim që nuk ka ndikim në rendin.
Operatori utilitar share është në gjendje të bëjë nga një rrjedhë të ftohtë një rrjedhë të ngrohtë.

Me operatorët përfunduam. Tani do të kalojmë te Subject.
Të mendojmë në zë
Dhe kĂ«tu shkova tĂ« pi çaj. MĂ« lodhĂ«n kĂ«to shembuj đ
Familja e subject-ëve
Familja e subject-ëve është një shembull i shkëlqyer i rrjedhave të ngrohta. Këto klasa janë një hibrid, që veprojnë njëherazi si observable dhe observer. Duke qenë se subject është një rrjedhë e ngrohtë, është e nevojshme të mbahen në mend se duhet të shkëputeni. Në lidhje me metodat kryesore, ato janë:
- next â dĂ«rgimi i tĂ« dhĂ«nave tĂ« reja nĂ« rrjedhĂ«
- error â gabim dhe pĂ«rfundimi i rrjedhĂ«s
- complete â pĂ«rfundimi i rrjedhĂ«s
- subscribe â abonohem nĂ« rrjedhĂ«
- unsubscribe â shkĂ«putem nga rrjedha
- asObservable â e transformojmĂ« nĂ« njĂ« vĂ«zhgues
- toPromise â e transformon nĂ« njĂ« premtim
Dallohet 4-5 lloje subject-ësh.
Të mendojmë në zë
Në stream thashë 4, por doli se ata kanë shtuar një tjetër. Siç thonë, jeton dhe mëso!
Subject i thjeshtĂ« new Subject()â lloji mĂ« i thjeshtĂ« i subject-eve. Krijohet pa parametra. Transmeton vlerat qĂ« vijnĂ« vetĂ«m pas abonimit.
BehaviorSubject new BehaviorSubject( defaultData ) â sipas mendimit tim, lloji mĂ« i zakonshĂ«m i subject-eve. Merr njĂ« vlerĂ« fillestare. GjithmonĂ« ruan tĂ« dhĂ«nat e lĂ«shimit tĂ« fundit, tĂ« cilat i transmeton gjatĂ« abonimit. Ky klas ka gjithashtu njĂ« metodĂ« tĂ« dobishme value, e cila kthen vlerĂ«n aktuale tĂ« rrjedhĂ«s.
ReplaySubject new ReplaySubject(bufferSize?: number, windowTime?: number) â Mund tĂ« marrĂ« si argument tĂ« parĂ« opsional madhĂ«sinĂ« e tamponit tĂ« vlerave qĂ« do tĂ« mbajĂ«, dhe si tĂ« dytĂ« kohĂ«n gjatĂ« sĂ« cilĂ«s na nevojiten ndryshimet.
AsyncSubject new AsyncSubject() â gjatĂ« abonimit nuk ndodh asgjĂ«, dhe vlera do tĂ« kthehet vetĂ«m kur tĂ« pĂ«rfundojĂ«. Do tĂ« kthehet vetĂ«m vlera e fundit e rrjedhĂ«s.
WebSocketSubject new WebSocketSubject(urlConfigOrSource: string | WebSocketSubjectConfig | Observable, destination?: Observer) â Dokumentacioni nuk thotĂ« asgjĂ« pĂ«r tĂ«, dhe unĂ« e shoh pĂ«r herĂ« tĂ« parĂ«. Kush e di se çfarĂ« bĂ«n, ju lutem shkruani, do ta plotĂ«sojmĂ«.
Ah, kështu që ne kemi shqyrtuar gjithçka që doja të ndaja sot. Shpresoj që kjo informacion të ketë qenë e dobishme. Mund të shqyrtoni listën e literaturës në seksionin e informacionit të dobishëm.
Informacion i dobishëm
- â lidhje me stream-in
- â Si funksionon JS: njĂ« pĂ«rmbledhje e motorit, mekanizmave tĂ« ekzekutimit, stack-ut tĂ« thirrjeve
- â Si funksionon JS: cikli i ngjarjeve, asinkronia dhe pesĂ« mĂ«nyra pĂ«r tĂ« pĂ«rmirĂ«suar kodin me async / await
- â Si funksionon Event Loop nĂ« JavaScript
- â Evolucioni i JavaScript-it asinkron
- â ĂfarĂ« Ă«shtĂ« RxJS dhe pĂ«rse Ă«shtĂ« e rĂ«ndĂ«sishme tĂ« dihet pĂ«r tĂ«
- â PĂ«rdorimi praktike i RxJS
- â Tutoriali i RxJS Observables â Krijimi dhe NĂ«nshkrimi nĂ« Observables
- â RXJS: Observables tĂ« Nxehta dhe tĂ« Ftohta
- â Klasa, funksione pĂ«r krijimin e Observable. OperatorĂ«t.
- â OperatorĂ«t e RxJS sipas shembujve
- â Lista e API-ve
- â Llojet e Subject dhe Orare nĂ« RxJS
Burimi: habr.com
