Асинхронное программирование в JavaScript (Callback, Promise, RxJs )
Hi kollha. Sergey Omelnitsky huwa f'kuntatt. Ftit ilu ospitajt nixxiegħa dwar l-ipprogrammar reattiv, fejn tkellimt dwar l-asynchrony fil-JavaScript. Illum nixtieq nieħu noti dwar dan il-materjal.
Iżda qabel ma nibdew il-materjal ewlieni, irridu nagħmlu nota introduttorja. Mela ejja nibdew bid-definizzjonijiet: x'inhu munzell u kju?
Munzell hija kollezzjoni li l-elementi tagħha huma miksuba fuq bażi LIFO tal-aħħar li jidħol, li joħroġ l-ewwel
Kju hija kollezzjoni li l-elementi tagħha huma miksuba fuq bażi FIFO first-in, first-out
Tajjeb, ejja nkomplu.
JavaScript hija lingwa ta' programmar b'ħajt wieħed. Dan ifisser li hemm ħajt wieħed biss ta 'eżekuzzjoni u munzell wieħed li fuqu l-funzjonijiet huma kju għall-eżekuzzjoni. Għalhekk, JavaScript jista 'jwettaq biss operazzjoni waħda kull darba, filwaqt li operazzjonijiet oħra se jistennew min-naħa tagħhom fuq il-munzell sakemm jissejħu.
Sejħa munzell hija struttura tad-dejta li, sempliċiment, tirreġistra informazzjoni dwar il-post fil-programm fejn aħna. Jekk ngħaddu għal funzjoni, aħna nimbottaw id-dħul tagħha fil-quċċata tal-munzell. Meta nerġgħu lura minn funzjoni, aħna pop l-element ta 'fuq mill-munzell u jispiċċaw lura fejn sejjaħ il-funzjoni. Dan huwa dak kollu li jista 'jagħmel il-munzell. U issa mistoqsija estremament interessanti. Kif taħdem l-asinkronija fil-JavasScript?
Fil-fatt, minbarra l-munzell, il-browsers għandhom kju speċjali biex jaħdmu ma 'l-hekk imsejjaħ WebAPI. Il-funzjonijiet f'dan il-kju se jiġu eżegwiti fl-ordni biss wara li l-munzell ikun ġie kompletament imnaddaf. Wara dan biss huma mbuttati mill-kju fuq il-munzell għall-eżekuzzjoni. Jekk hemm mill-inqas element wieħed fuq il-munzell fil-mument, allura ma jistgħux jiġu miżjuda mal-munzell. Huwa preċiżament minħabba dan li s-sejħa ta 'funzjonijiet permezz ta' timeout ħafna drabi ma tkunx preċiża fil-ħin, peress li l-funzjoni ma tistax tikseb mill-kju għall-munzell waqt li tkun mimlija.
Рассмотрим следующий пример и займёмся его пошаговым «выполнением». Также посмотрим, что при этом происходит в системе.
Ukoll, ħares lejn kif l-asinkronija hija implimentata fil-JavaScript. Issa ejja nitkellmu fil-qosor dwar l-evoluzzjoni tal-kodiċi mhux sinkroniku.
L-evoluzzjoni tal-kodiċi mhux sinkroniku.
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);
})
})
})
})
})
});
L-ipprogrammar asinkroniku kif nafuh f'JavaScript jista' jiġi implimentat biss minn funzjonijiet. Jistgħu jiġu mgħoddija bħal kull varjabbli oħra għal funzjonijiet oħra. Hekk twieldu callbacks. U jibred, pjaċevoli u jilgħab, sakemm jinbidel f’dwejjaq, melankoniku u dwejjaq. Għaliex? Huwa sempliċi:
Hekk kif il-kumplessità tal-kodiċi tiżdied, il-proġett malajr jinbidel fi blokki oskuri, ripetutament imnaqqxa - "callback hell".
Immaniġġjar ta 'żbalji jista' jkun faċli li titlifha.
Ma tistax tirritorna espressjonijiet b'ritorn.
Bil-miġja tal-Wegħda, is-sitwazzjoni saret ftit aħjar.
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);
});
Dehru ktajjen tal-wegħda, li tejbu l-leġibbiltà tal-kodiċi
Deher metodu separat biex jinqabdu l-iżbalji
Miżjud il-possibbiltà ta 'eżekuzzjoni parallela bl-użu ta' Promise.all
Nistgħu nsolvu l-asynchrony nested billi tuża async/wait
Iżda l-wegħdiet għandhom il-limitazzjonijiet tagħhom. Pereżempju, wegħda ma tistax tiġi kkanċellata mingħajr żfin b'tambourine, u l-aktar importanti huwa li taħdem b'valur wieħed.
Ukoll, avviċinajna bla xkiel l-ipprogrammar reattiv. Għajjien? Ukoll, fortunatament, tista 'tmur tagħmel ftit tè, taħseb dwarha u terġa' taqra aktar. U se nkompli.
Programmazzjoni reattiva hija paradigma ta' programmazzjoni ffukata fuq il-flussi tad-dejta u l-propagazzjoni tal-bidla. Ejja nagħtu ħarsa aktar mill-qrib lejn x'inhu fluss tad-dejta.
// Получаем ссылку на элемент
const input = ducument.querySelector('input');
const eventsArray = [];
// Пушим каждое событие в массив eventsArray
input.addEventListener('keyup',
event => eventsArray.push(event)
);
Ejja nimmaġinaw li għandna input field. Qed noħolqu firxa u għal kull keyup tal-avveniment tal-input aħna se naħżnu l-avveniment fil-firxa tagħna. Fl-istess ħin, nixtieq ninnota li l-firxa tagħna hija magħżula skond il-ħin, i.e. l-indiċi ta 'avvenimenti aktar tard huwa akbar mill-indiċi ta' dawk preċedenti. Array bħal dan huwa mudell simplifikat ta 'fluss ta' dejta, iżda għadu mhux fluss. Sabiex din l-array tissejjaħ b'mod sikur fluss, għandu jkun jista 'b'xi mod jinforma lill-abbonati li data ġdida waslet fiha. Għalhekk naslu għad-definizzjoni ta 'fluss.
Fluss hija firxa ta' dejta magħżula skont il-ħin li tista' tindika li d-dejta nbidlet. Issa immaġina kemm isir konvenjenti li tikteb kodiċi li fiha azzjoni waħda teħtieġ li ssejjaħ diversi avvenimenti f'partijiet differenti tal-kodiċi. Aħna sempliċement tabbona għall-fluss u tinnotifikana meta jseħħu bidliet. U l-librerija RxJs tista 'tagħmel dan.
RxJS hija librerija biex taħdem ma 'programmi asinkroniċi u bbażati fuq avvenimenti li jużaw sekwenzi osservabbli. Il-librerija tipprovdi tip bażiku Osservabbli, diversi tipi awżiljarji (Osservatur, Schedulers, Suġġetti) u operaturi biex jaħdmu ma' avvenimenti bħal ma' kollezzjonijiet (mappa, iffiltra, tnaqqas, kull u oħrajn simili minn JavaScript Array).
Ejja nifhmu l-kunċetti bażiċi ta 'din il-librerija.
Osservabbli, Osservatur, Produttur
Osservabbli huwa l-ewwel tip bażiku li ser inħarsu lejh. Din il-klassi fiha l-parti prinċipali tal-implimentazzjoni RxJs. Huwa assoċjat ma 'fluss osservabbli, li jista' jiġi sottoskritt bl-użu tal-metodu ta 'sottoskrizzjoni.
Observable timplimenta mekkaniżmu helper għall-ħolqien ta 'aġġornamenti, l-hekk imsejħa Osservatur. Is-sors tal-valuri għall-Osservatur jissejjaħ Produttur. Dan jista 'jkun firxa, iteratur, socket tal-web, xi tip ta' avveniment, eċċ. Allura nistgħu ngħidu li osservabbli huwa konduttur bejn Producer u Observer.
Observable jimmaniġġja tliet tipi ta' avvenimenti tal-Osservatur:
li jmiss - data ġdida
żball – żball jekk is-sekwenza ntemmet minħabba eċċezzjoni. dan l-avveniment jimplika wkoll it-tlestija tas-sekwenza.
kompluta — sinjal dwar it-tlestija tas-sekwenza. Dan ifisser li mhux se jkun hemm aktar data ġdida.
Ejja naraw id-demo:
Fil-bidu ser nipproċessaw il-valuri 1, 2, 3, u wara 1 sekonda. se nġibu 4 u nispiċċaw il-fluss tagħna.
Taħseb b'leħen għoli
U mbagħad indunajt li li tgħidha kien aktar interessanti milli nikteb dwarha. 😀
abbonament
Meta aħna tabbona għal stream noħolqu klassi ġdida sottoskrizzjonili tagħtina l-abbiltà li unsubscribe bl-użu tal-metodu unsubscribe. Nistgħu wkoll niġbru l-abbonamenti bl-użu tal-metodu żid. Ukoll, huwa loġiku li nistgħu inseparaw il-ħjut bl-użu neħħi. Il-metodi żid u neħħi jaċċettaw abbonament ieħor bħala input. Nixtieq ninnota li meta aħna unsubscribe, aħna unsubscribe mill-abbonamenti tat-tfal kollha bħallikieku kienu sejħu l-unsubscribe metodu. Aqbad.
Tipi ta 'flussi
HOT
Kessaħ
Produttur hija maħluqa barra osservabbli
Produttur hija maħluqa ġewwa osservabbli
Id-dejta tiġi trasferita fil-ħin li jinħoloq l-osservabbli
Id-dejta hija pprovduta fil-ħin tal-abbonament
Bżonn loġika addizzjonali biex tneħħi l-abbonament
Il-ħajt jintemm waħdu
Juża relazzjoni waħda għal ħafna
Juża relazzjoni waħda għal waħda
L-abbonamenti kollha għandhom l-istess tifsira
L-abbonamenti huma indipendenti
Id-dejta tista' tintilef jekk ma jkollokx abbonament
Joħroġ mill-ġdid il-valuri kollha tal-fluss għal abbonament ġdid
Biex nagħti analoġija, naħseb ta 'fluss sħun bħala film f'teatru. F'liema ħin wasalt, minn dak il-mument bdejt tara. Nixtieq inqabbel fluss kiesaħ ma 'sejħa fit-teknoloġija. appoġġ. Kull min iċempel jisma' r-reġistrazzjoni tal-voicemail mill-bidu sat-tmiem, iżda tista' twaqqaf billi tuża unsubscribe.
Nixtieq ninnota li hemm ukoll l-hekk imsejħa flussi sħun (iltqajt ma 'din id-definizzjoni estremament rari u biss f'komunitajiet barranin) - dan huwa fluss li jittrasforma minn fluss kiesaħ għal wieħed sħun. Tqum il-mistoqsija - fejn tuża)) Se nagħti eżempju mill-prattika.
Qed naħdem ma 'Angular. Huwa juża b'mod attiv rxjs. Biex tirċievi dejta lis-server, nistenna ħajt kiesaħ u nuża dan il-ħajt fil-mudell bl-użu ta 'asyncPipe. Jekk nuża dan il-pajp diversi drabi, imbagħad, nirritorna għad-definizzjoni ta 'nixxiegħa kiesħa, kull pajp se jitlob dejta mis-server, li hija stramba biex ngħidu l-inqas. U jekk nikkonverti nixxiegħa kiesħa f'waħda sħuna, allura t-talba sseħħ darba.
B'mod ġenerali, il-fehim tat-tip ta 'flussi huwa pjuttost diffiċli għal dawk li jibdew, iżda importanti.
Operaturi
return this.http.get(`${environment.apiUrl}/${this.apiUrl}/trade_companies`)
.pipe(
tap(({ data }: TradeCompanyList) => this.companies$$.next(cloneDeep(data))),
map(({ data }: TradeCompanyList) => data)
);
L-operaturi jipprovdulna l-abbiltà li nespandu l-kapaċità tagħna li naħdmu ma 'flussi. Jgħinu biex jikkontrollaw l-avvenimenti li jseħħu fl-Osservabbli. Se nħarsu lejn ftit mill-aktar popolari, u aktar dettalji dwar l-operaturi jistgħu jinstabu billi tuża l-links fl-informazzjoni utli.
Operaturi - ta'
Nibdew bl-operatur awżiljarju ta '. Joħloq Osservabbli bbażat fuq valur sempliċi.
Operaturi - filtru
L-operatur tal-filtru, kif jissuġġerixxi l-isem, jiffiltra s-sinjal tan-nixxiegħa. Jekk l-operatur jirritorna veru, jaqbeż aktar.
Operaturi - jieħdu
take — Jieħu l-valur tan-numru ta 'emittenti, u wara jispiċċa l-ħajta.
Operaturi - debounceTime
debounceTime - jarmi l-valuri emessi li jaqgħu fl-intervall ta 'żmien speċifikat bejn l-outputs - wara li l-intervall ta' ħin ikun għadda, jarmi l-aħħar valur.
const { Observable } = Rx;
const { debounceTime, take } = RxOperators;
Observable.create((observer) => {
let i = 1;
observer.next(i++);
// Испускаем значение раз в 1000мс
setInterval(() => {
observer.next(i++)
}, 1000);
// Испускаем значение раз в 1500мс
setInterval(() => {
observer.next(i++)
}, 1500);
}).pipe(
debounceTime(700), // Ожидаем 700мс значения прежде чем обработать
take(3)
);
Operaturi - takeWhile
Jarmi valuri sakemm takeWhile jirritorna falza, u wara jneħħi l-abbonament mill-ħajt.
const { Observable } = Rx;
const { debounceTime, takeWhile } = RxOperators;
Observable.create((observer) => {
let i = 1;
observer.next(i++);
// Испускаем значение раз в 1000мс
setInterval(() => {
observer.next(i++)
}, 1000);
}).pipe(
takeWhile( producer => producer < 5 )
);
Operaturi - combineLatest
Комбинированный оператор combineLatest чем-то похож на promise.all. Он объединяет несколько потоков в один. После того как каждый поток сделает хотя бы один эмит, мы получаем последние значения от каждого в виде массива. Далее, после любого эмита из объединённых потоков он будет отдавать новые значения.
const { combineLatest, Observable } = Rx;
const { take } = RxOperators;
const observer_1 = Observable.create((observer) => {
let i = 1;
// Испускаем значение раз в 1000мс
setInterval(() => {
observer.next('a: ' + i++);
}, 1000);
});
const observer_2 = Observable.create((observer) => {
let i = 1;
// Испускаем значение раз в 750мс
setInterval(() => {
observer.next('b: ' + i++);
}, 750);
});
combineLatest(observer_1, observer_2).pipe(take(5));
Operaturi - zip
Zip - Tistenna valur minn kull ħajta u tifforma firxa bbażata fuq dawn il-valuri. Jekk il-valur ma jiġix minn xi ħajta, allura l-grupp mhux se jiġi ffurmat.
const { zip, Observable } = Rx;
const { take } = RxOperators;
const observer_1 = Observable.create((observer) => {
let i = 1;
// Испускаем значение раз в 1000мс
setInterval(() => {
observer.next('a: ' + i++);
}, 1000);
});
const observer_2 = Observable.create((observer) => {
let i = 1;
// Испускаем значение раз в 750
setInterval(() => {
observer.next('b: ' + i++);
}, 750);
});
const observer_3 = Observable.create((observer) => {
let i = 1;
// Испускаем значение раз в 500
setInterval(() => {
observer.next('c: ' + i++);
}, 500);
});
zip(observer_1, observer_2, observer_3).pipe(take(5));
Operaturi - forkJoin
forkJoin jingħaqad ukoll mal-ħjut, iżda jarmi valur biss meta l-ħjut kollha jkunu kompluti.
const { forkJoin, Observable } = Rx;
const { take } = RxOperators;
const observer_1 = Observable.create((observer) => {
let i = 1;
// Испускаем значение раз в 1000мс
setInterval(() => {
observer.next('a: ' + i++);
}, 1000);
}).pipe(take(3));
const observer_2 = Observable.create((observer) => {
let i = 1;
// Испускаем значение раз в 750
setInterval(() => {
observer.next('b: ' + i++);
}, 750);
}).pipe(take(5));
const observer_3 = Observable.create((observer) => {
let i = 1;
// Испускаем значение раз в 500
setInterval(() => {
observer.next('c: ' + i++);
}, 500);
}).pipe(take(4));
forkJoin(observer_1, observer_2, observer_3);
const { Observable } = Rx;
const { take, map } = RxOperators;
Observable.create((observer) => {
let i = 1;
// Испускаем значение раз в 1000мс
setInterval(() => {
observer.next(i++);
}, 1000);
}).pipe(
map(x => x * 10),
take(3)
);
Operaturi – jaqsmu, tektek
L-operatur tal-vit jippermettilek li tagħmel effetti sekondarji, jiġifieri, kwalunkwe azzjonijiet li ma jaffettwawx is-sekwenza.
L-operatur tal-utilità tal-ishma jista 'jbiddel nixxiegħa kiesħa f'waħda sħuna.
Għamilna l-operaturi. Ejja ngħaddu għas-Suġġett.
Taħseb b'leħen għoli
U mbagħad mort nixrob ftit tè. Għajjien b'dawn l-eżempji 😀
Familja tas-suġġett
Il-familja tas-suġġett hija eżempju ewlieni ta 'flussi sħan. Dawn il-klassijiet huma tip ta 'ibridi li jaġixxu simultanjament bħala osservabbli u osservatur. Peress li s-suġġett huwa hot thread, huwa meħtieġ li tneħħi l-abbonament minnu. Jekk nitkellmu dwar il-metodi ewlenin, allura dawn huma:
li jmiss - trasferiment ta 'data ġdida għall-fluss
żball - żball u terminazzjoni tal-ħajt
kompluta – tlestija tal-ħajta
abbona – abbona għal nixxiegħa
unsubscribe – unsubscribe mill-fluss
asObservable - tittrasforma f'osservatur
toPromise – tittrasforma f’wegħda
Hemm 4 5 tipi ta 'suġġetti.
Taħseb b'leħen għoli
Kien hemm 4 nies jitkellmu fuq in-nixxiegħa, iżda rriżulta li żiedu waħda oħra. Kif jgħidu, għix u tgħallem.
Suġġett sempliċi new Subject()– l-aktar tip sempliċi ta’ suġġetti. Maħluq mingħajr parametri. Jitrażmetti valuri riċevuti biss wara l-abbonament.
ImġiebaSuġġett new BehaviorSubject( defaultData<T> ) – fl-opinjoni tiegħi, l-aktar tip ta’ suġġett komuni. L-input jieħu l-valur default. Dejjem jiffranka d-dejta tal-aħħar ħarġa, li tiġi trażmessa meta tissottoskrivi. Din il-klassi għandha wkoll metodu ta 'valur utli, li jirritorna l-valur kurrenti tal-fluss.
ReplaySuġġett new ReplaySubject(bufferSize?: number, windowTime?: number) — L-input jista’ b’għażla jieħu bħala l-ewwel argument id-daqs tal-buffer ta’ valuri li se jaħżen fih innifsu, u bħala t-tieni iż-żmien li fih għandna bżonn bidliet.
AsyncSubject new AsyncSubject() — ma jiġri xejn meta tissottoskrivi, u l-valur jiġi rritornat biss meta jkun komplut. L-aħħar valur tan-nixxiegħa biss se jiġi rritornat.
WebSocketSubject new WebSocketSubject(urlConfigOrSource: string | WebSocketSubjectConfig<T> | Observable<T>, destination?: Observer<T>) — Id-dokumentazzjoni hija siekta dwaru u qed narah għall-ewwel darba. Jekk xi ħadd jaf x'jagħmel, jekk jogħġbok ikteb u nżiduh.
Phew. Ukoll, koprejna dak kollu li ridt ngħidilkom illum. Nispera li din l-informazzjoni kienet utli. Tista' taqra l-lista tar-referenzi lilek innifsek fit-tab ta' informazzjoni utli.