JavaScript-da asinxron dasturlash (callback, Promise, RxJs)
Hammaga salom. Sergey Omelnitskiy aloqada. Yaqinda men reaktiv dasturlash bo'yicha oqim o'tkazdim, u erda JavaScript-da asinxroniya haqida gapirdim. Bugun men ushbu materialga eslatma olishni xohlayman.
Lekin asosiy materialni boshlashdan oldin, biz kirish yozuvini yozishimiz kerak. Keling, ta'riflardan boshlaylik: stek va navbat nima?
Stak elementlari oxirgi kiruvchi, birinchi boβlib LIFO asosida olinadigan toβplamdir
Navbat elementlari birinchi bo'lib FIFO asosida olinadigan to'plamdir
Mayli, davom etaylik.
JavaScript - bu bitta oqimli dasturlash tili. Bu shuni anglatadiki, faqat bitta bajarilish ipi va vazifalar bajarish uchun navbatga qo'yilgan bitta stek mavjud. Shuning uchun, JavaScript bir vaqtning o'zida faqat bitta operatsiyani bajarishi mumkin, boshqa operatsiyalar esa chaqirilguncha stekda o'z navbatini kutadi.
Qo'ng'iroqlar to'plami oddiy qilib aytganda, biz joylashgan dasturdagi joy haqidagi ma'lumotlarni yozib oladigan ma'lumotlar tuzilmasi. Agar biz funktsiyaga o'tsak, uning kirishini stekning yuqori qismiga suramiz. Funktsiyadan qaytganimizda, biz stekdan eng yuqori elementni chiqaramiz va funksiyani chaqirgan joyga qaytamiz. Bu stek qila oladigan barcha narsa. Va endi juda qiziq savol. JavasScript-da asinxroniya qanday ishlaydi?
Aslida, stekga qo'shimcha ravishda, brauzerlarda WebAPI deb ataladigan dastur bilan ishlash uchun maxsus navbat mavjud. Bu navbatdagi funksiyalar stek toΚ»liq tozalangandan keyingina tartibda bajariladi. Shundan keyingina ular bajarish uchun navbatdan stekga suriladi. Agar hozirda stekda kamida bitta element mavjud bo'lsa, ularni stekga qo'shib bo'lmaydi. Aynan shuning uchun funksiyalarni vaqt tugashi bilan chaqirish ko'pincha vaqtida aniq bo'lmaydi, chunki funksiya to'lgan paytda navbatdan stekga kira olmaydi.
Keling, quyidagi misolni ko'rib chiqamiz va uning bosqichma-bosqich bajarilishini boshlaymiz. Keling, tizimda nima sodir bo'lishini ham ko'rib chiqaylik.
1) Hali hech narsa sodir bo'lmadi. Brauzer konsoli aniq, qo'ng'iroqlar to'plami bo'sh.
2) Keyin qo'ng'iroqlar stekiga console.log('Hi') buyrug'i qo'shiladi.
3) Va u amalga oshdi
4) Keyin console.log('Hi') qo'ng'iroqlar to'plamidan o'chiriladi.
5) Endi setTimeout (funktsiya cb1() {β¦ }) buyrug'iga o'ting. U qo'ng'iroqlar to'plamiga qo'shiladi.
6) setTimeout(funksiya cb1() {β¦ }) buyrug'i bajariladi. Brauzer Web API ning bir qismi bo'lgan taymerni yaratadi. U orqaga hisoblashni amalga oshiradi.
7) setTimeout(funksiya cb1() {... }) buyrug'i o'z ishini tugatdi va qo'ng'iroqlar stekidan olib tashlandi.
8) Console.log('Bye') buyrug'i qo'ng'iroqlar to'plamiga qo'shiladi.
Xo'sh, biz JavaScript-da asinxroniya qanday amalga oshirilishini ko'rib chiqdik. Endi asinxron kodning evolyutsiyasi haqida qisqacha gaplashamiz.
Asinxron kodning evolyutsiyasi.
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);
})
})
})
})
})
});
Biz JavaScript-da bilganimizdek, asinxron dasturlash faqat funksiyalar tomonidan amalga oshirilishi mumkin. Ular boshqa o'zgaruvchilar kabi boshqa funktsiyalarga o'tkazilishi mumkin. Qayta qo'ng'iroqlar shunday tug'ildi. Va u qayg'u, melankolik va qayg'uga aylanmaguncha, salqin, qiziqarli va o'ynoqi. Nega? Bu oddiy:
Kodning murakkabligi oshgani sayin, loyiha tezda noaniq, qayta-qayta joylashtirilgan bloklarga aylanadi - "qayta qo'ng'iroq qilish do'zaxi".
Xatolarni ko'rib chiqish oson bo'lishi mumkin.
Qaytish bilan ifodalarni qaytara olmaysiz.
Promise paydo bo'lishi bilan vaziyat biroz yaxshilandi.
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);
});
Va'da zanjirlari paydo bo'ldi, bu kodni o'qishni yaxshiladi
Xatolarni aniqlashning alohida usuli paydo bo'ldi
Promise.all yordamida parallel bajarish imkoniyati qo'shildi
Biz async/await yordamida ichki asinxroniyani hal qilishimiz mumkin
Ammo va'dalarning o'z chegaralari bor. Misol uchun, va'dani daf bilan raqsga tushmasdan bekor qilib bo'lmaydi va eng muhimi, u bitta qiymat bilan ishlaydi.
Xo'sh, biz reaktiv dasturlashga muammosiz yaqinlashdik. Charchadimi? Yaxshiyamki, siz borib choy qaynatib, o'ylab ko'ring va ko'proq o'qish uchun qaytib keling. Va men davom etaman.
Reaktiv dasturlashβma'lumotlar oqimi va o'zgarishlarning tarqalishiga qaratilgan dasturlash paradigmasi. Keling, ma'lumotlar oqimi nima ekanligini batafsil ko'rib chiqaylik.
Tasavvur qilaylik, bizda kirish maydoni bor. Biz massiv yaratmoqdamiz va kirish hodisasining har bir kaliti uchun biz voqeani massivimizda saqlaymiz. Shu bilan birga, shuni ta'kidlashni istardimki, bizning massivimiz vaqt bo'yicha tartiblangan, ya'ni. keyingi voqealar ko'rsatkichi oldingi voqealar indeksidan kattaroqdir. Bunday massiv ma'lumotlar oqimining soddalashtirilgan modelidir, lekin u hali oqim emas. Ushbu massivni xavfsiz oqim deb atash uchun u qandaydir tarzda obunachilarga yangi ma'lumotlar kelganligi haqida xabar bera olishi kerak. Shunday qilib, biz oqim ta'rifiga keldik.
Oqimβma'lumotlarning o'zgarganligini ko'rsatishi mumkin bo'lgan vaqt bo'yicha tartiblangan ma'lumotlar massivi. Endi tasavvur qiling-a, kodni yozish qanchalik qulay bo'ladi, unda bitta amal kodning turli qismlarida bir nechta hodisalarni chaqirishni talab qiladi. Biz shunchaki oqimga obuna bo'lamiz va u o'zgarishlar sodir bo'lganda bizga xabar beradi. Va RxJs kutubxonasi buni qila oladi.
RxJS kuzatilishi mumkin bo'lgan ketma-ketliklardan foydalangan holda asinxron va hodisalarga asoslangan dasturlar bilan ishlash uchun kutubxona. Kutubxona asosiy turni taqdim etadi Kuzatiladigan, bir nechta yordamchi turlari (Kuzatuvchi, jadval tuzuvchilar, sub'ektlar) va hodisalar bilan to'plamlar bilan ishlash uchun operatorlar (xarita, filtrlash, kamaytirish, har bir va shunga o'xshashlar JavaScript massividan).
Keling, ushbu kutubxonaning asosiy tushunchalarini tushunaylik.
Kuzatiladigan, kuzatuvchi, ishlab chiqaruvchi
Kuzatiladigan - biz ko'rib chiqadigan birinchi asosiy tur. Bu sinf RxJs amalga oshirishning asosiy qismini o'z ichiga oladi. U obuna usuli yordamida obuna bo'lishi mumkin bo'lgan kuzatilishi mumkin bo'lgan oqim bilan bog'liq.
Observable yangilanishlarni yaratish uchun yordamchi mexanizmni amalga oshiradi Kuzatuvchi. Observer uchun qiymatlar manbai deyiladi ishlab chiqaruvchi. Bu massiv, iterator, veb-rozetka, qandaydir hodisa va boshqalar bo'lishi mumkin. Shunday qilib, biz kuzatilishi mumkin bo'lgan prodyuser va kuzatuvchi o'rtasidagi dirijyor deb ayta olamiz.
Kuzatiladigan observer hodisalarining uch turini boshqaradi:
keyingi - yangi ma'lumotlar
xato - agar ketma-ketlik istisno tufayli tugagan bo'lsa, xato. bu hodisa ham ketma-ketlikning tugallanishini nazarda tutadi.
to'liq - ketma-ketlikning tugashi haqida signal. Bu endi yangi ma'lumotlar bo'lmaydi, degan ma'noni anglatadi.
Keling, demoni ko'rib chiqaylik:
Boshida biz 1, 2, 3 va 1 soniyadan keyin qiymatlarni qayta ishlaymiz. biz 4 ni olamiz va oqimimizni tugatamiz.
Ovoz chiqarib o'ylash
Va keyin men bu haqda yozishdan ko'ra aytish qiziqroq ekanligini angladim. π
obuna
Oqimga obuna bo'lganimizda biz yangi sinf yaratamiz obunabu usul yordamida obunani bekor qilish imkoniyatini beradi obunani bekor qilish. Usul yordamida obunalarni guruhlashimiz ham mumkin qo'shish. Xo'sh, biz yordamida iplarni ajratishimiz mantiqan to'g'ri olib tashlash. Qo'shish va o'chirish usullari kirish sifatida boshqa obunani qabul qiladi. Shuni ta'kidlashni istardimki, biz obunani bekor qilganimizda, biz barcha bolalar obunalarini obunani bekor qilish usulini chaqirgandek bekor qilamiz. Davom etishga ruxsat.
Oqim turlari
HOT
SOVUQ
Ishlab chiqaruvchi kuzatilishi mumkin bo'lmagan holda yaratilgan
Ishlab chiqaruvchi kuzatiladigan ichida yaratilgan
Ma'lumotlar kuzatilishi mumkin bo'lgan narsa yaratilgan vaqtda uzatiladi
Ma'lumotlar obuna vaqtida taqdim etiladi
Obunani bekor qilish uchun qo'shimcha mantiq kerak
Ip o'z-o'zidan tugaydi
Birga koβp munosabatdan foydalanadi
Birga-bir munosabatdan foydalanadi
Barcha obunalar bir xil ma'noga ega
Obunalar mustaqil
Obuna bo'lmasa, ma'lumotlar yo'qolishi mumkin
Yangi obuna uchun barcha oqim qiymatlarini qayta chiqaradi
O'xshatish uchun, men qaynoq oqimni teatrdagi kino deb o'ylagan bo'lardim. Qaysi vaqtda keldingiz, o'sha paytdan boshlab tomosha qila boshladingiz. Men sovuq oqimni texnologiyadagi qo'ng'iroq bilan solishtiraman. qo'llab-quvvatlash. Har qanday qo'ng'iroq qiluvchi ovozli pochta yozuvini boshidan oxirigacha tinglaydi, lekin siz obunani bekor qilish orqali telefonni o'chirib qo'yishingiz mumkin.
Shuni ta'kidlashni istardimki, iliq oqimlar ham mavjud (men bu ta'rifni juda kamdan-kam hollarda uchratganman va faqat xorijiy jamoalarda) - bu sovuq oqimdan issiq oqimga aylanadigan oqim. Savol tug'iladi - qaerdan foydalanish kerak)) Men amaliyotdan misol keltiraman.
Men Angular bilan ishlayapman. U rxjs dan faol foydalanadi. Serverga ma'lumotlarni qabul qilish uchun men sovuq ipni kutaman va asyncPipe yordamida shablonda ushbu ipdan foydalanaman. Agar men ushbu trubani bir necha marta ishlatsam, sovuq oqimning ta'rifiga qaytsak, har bir quvur serverdan ma'lumotlarni so'raydi, bu juda g'alati. Va agar men sovuq oqimni issiqqa aylantirsam, so'rov bir marta amalga oshiriladi.
Umuman olganda, yangi boshlanuvchilar uchun oqim turini tushunish juda qiyin, ammo muhim.
Operatorlar
return this.http.get(`${environment.apiUrl}/${this.apiUrl}/trade_companies`)
.pipe(
tap(({ data }: TradeCompanyList) => this.companies$$.next(cloneDeep(data))),
map(({ data }: TradeCompanyList) => data)
);
Operatorlar bizga oqimlar bilan ishlash qobiliyatimizni kengaytirish imkoniyatini beradi. Ular kuzatilishi mumkin bo'lgan voqealarni boshqarishga yordam beradi. Biz eng mashhurlaridan bir nechtasini ko'rib chiqamiz va siz foydali ma'lumotlardagi havolalar orqali operatorlar haqida ko'proq ma'lumot olishingiz mumkin.
Operatorlar - of
ning yordamchi operatoridan boshlaylik. U oddiy qiymat asosida Kuzatiladiganni yaratadi.
Operatorlar - filtr
Filtr operatori, nomidan ko'rinib turibdiki, oqim signalini filtrlaydi. Agar operator true qiymatini qaytarsa, u yana o'tkazib yuboradi.
Operatorlar - oling
take - Emitentlar sonining qiymatini oladi, shundan so'ng ip tugaydi.
Operatorlar - debounceTime
debounceTime - chiqishlar orasidagi belgilangan vaqt oralig'iga to'g'ri keladigan chiqarilgan qiymatlarni bekor qiladi - vaqt oralig'i o'tgandan so'ng, oxirgi qiymatni chiqaradi.
combineLatest operatori biroz o'xshash.all. U bir nechta iplarni birlashtiradi. Har bir ip kamida bitta emissiya qilgandan so'ng, biz har biridan massiv shaklida eng so'nggi qiymatlarni olamiz. Bundan tashqari, birlashtirilgan oqimlardan har qanday emissiyadan keyin u yangi qiymatlarni beradi.
Kran operatori sizga yon ta'sirlarni, ya'ni ketma-ketlikka ta'sir qilmaydigan har qanday harakatlarni amalga oshirishga imkon beradi.
Ulanish kommunal operatori sovuq oqimni issiqqa aylantirishi mumkin.
Biz operatorlar bilan ishlashni tugatdik. Keling, mavzuga o'tamiz.
Ovoz chiqarib o'ylash
Keyin choy ichishga bordim. Bu misollardan charchadim π
Mavzular oilasi
Mavzular oilasi issiq oqimlarning yorqin namunasidir. Bu sinflar bir vaqtning o'zida kuzatuvchi va kuzatuvchi sifatida harakat qiladigan o'ziga xos gibriddir. Mavzu qizg'in mavzu bo'lgani uchun undan obunani bekor qilish kerak. Agar asosiy usullar haqida gapiradigan bo'lsak, bular:
keyingi - yangi ma'lumotlarni oqimga o'tkazish
xato - xato va mavzuni tugatish
tugallangan - ipning tugallanishi
obuna bo'lish - oqimga obuna bo'lish
obunani bekor qilish - oqimdan obunani bekor qilish
asObservable - kuzatuvchiga aylantirish
toPromise - va'daga aylanadi
Mavzularning 4 5 turi mavjud.
Ovoz chiqarib o'ylash
Oqimda 4 kishi gaplashayotgan edi, lekin ular yana bir kishini qo'shib qo'yishdi. Ular aytganidek, yashang va o'rganing.
Oddiy mavzu new Subject()- mavzularning eng oddiy turi. Parametrlarsiz yaratilgan. Faqat obunadan keyin olingan qiymatlarni uzatadi.
BehaviorSubject new BehaviorSubject( defaultData<T> ) - menimcha, eng keng tarqalgan mavzu turi. Kirish standart qiymatni oladi. Har doim obuna bo'lganda uzatiladigan oxirgi nashrning ma'lumotlarini saqlaydi. Bu sinfda oqimning joriy qiymatini qaytaradigan foydali qiymat usuli ham mavjud.
ReplaySubject new ReplaySubject(bufferSize?: number, windowTime?: number) - Kirish ixtiyoriy ravishda birinchi argument sifatida u o'zida saqlaydigan qiymatlar buferining hajmini, ikkinchisi esa biz o'zgartirish kerak bo'lgan vaqtni olishi mumkin.
AsyncSubject new AsyncSubject() β obuna bo'lganda hech narsa sodir bo'lmaydi va qiymat faqat tugallangandan keyin qaytariladi. Oqimning faqat oxirgi qiymati qaytariladi.
WebSocketSubject new WebSocketSubject(urlConfigOrSource: string | WebSocketSubjectConfig<T> | Observable<T>, destination?: Observer<T>) - Hujjatlar u haqida jim va men uni birinchi marta ko'rmoqdaman. Agar kimdir nima bilan shug'ullanayotganini bilsa, yozing, biz uni qo'shamiz.
Voy. Xo'sh, bugun sizga aytmoqchi bo'lgan hamma narsani ko'rib chiqdik. Umid qilamanki, bu ma'lumot foydali bo'ldi. Foydali ma'lumotlar yorlig'ida havolalar ro'yxatini o'zingiz o'qishingiz mumkin.