Higher-order operatorlar
Higher-order operator — ichki Observable qaytaradigan Observable bilan ishlaydi. Angular'da HTTP zanjirlari, route param o'zgarishi va parallel/ketma-ket so'rovlar uchun eng muhim operatorlar guruhi.
switchMap — yangi kelsa eskini bekor qil (search)
Nima bu?
switchMap — tashqi Observable har yangi qiymat emit qilganda oldingi ichki Observable'ni unsubscribe qiladi va yangisiga o'tadi. Search, route param, filter o'zgarishi kabi holatlarda eski (keraksiz) HTTP javobini bekor qiladi — race condition va noto'g'ri natija oldini oladi. Faqat oxirgi so'rov natijasi muhim bo'lganda ishlatiladi.
Kod misoli
import { Component } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { switchMap, debounceTime, distinctUntilChanged } from 'rxjs/operators';
// Search — klassik switchMap
@Component({ /* ... */ })
export class ProductSearchComponent {
searchCtrl = new FormControl('');
products$ = this.searchCtrl.valueChanges.pipe(
debounceTime(300),
distinctUntilChanged(),
switchMap((query) =>
query ? this.http.get<Product[]>(`/api/search?q=${query}`) : of([])
)
);
}
// Route param — userId o'zgarganda eski user so'rovi bekor
@Component({ /* ... */ })
export class UserDetailComponent {
user$ = this.route.paramMap.pipe(
switchMap((params) => {
const id = params.get('id')!;
return this.http.get<User>(`/api/users/${id}`);
})
);
}
// Vizual: "a" → "ab" → "abc" tez yozilsa
// switchMap: faqat "abc" uchun HTTP natijasi qoladi
// mergeMap: uchtasi ham parallel, javob tartibi aralashishi mumkin
fromEvent(input, 'input').pipe(
map((e) => (e.target as HTMLInputElement).value),
switchMap((term) => this.api.search(term)) // ✅ search uchun
);
Imtihonda
- Search input uchun nima uchun switchMap, mergeMap emas?
- Route param o'zgarganda eski HTTP javobi yangisini bosib yuborishi mumkin — qanday oldini olinadi?
Yodlash uchun
switchMap = yangi kelsa eski bekor. Search, route param, filter — switchMap.
mergeMap — parallel ishla
Nima bu?
mergeMap (flatMap) — tashqi Observable har qiymati uchun yangi ichki Observable ochadi va barchasini parallel bajaradi. Oldingilar bekor qilinmaydi. Bir nechta mustaqil HTTP so'rov, har bir ID uchun alohida fetch, yoki bir vaqtda ko'p action bajarish kerak bo'lganda ishlatiladi. Javoblar kelish tartibida aralashishi mumkin.
Kod misoli
import { from, of } from 'rxjs';
import { mergeMap, map, toArray } from 'rxjs/operators';
// Bir nechta ID — parallel HTTP
const ids = [1, 2, 3, 4, 5];
from(ids)
.pipe(
mergeMap((id) => this.http.get<User>(`/api/users/${id}`)), // 5 ta parallel
toArray()
)
.subscribe((users) => console.log(users));
// Har bir fayl yuklash — barchasi parallel
from(selectedFiles)
.pipe(mergeMap((file) => this.uploadService.upload(file)))
.subscribe((progress) => this.updateProgress(progress));
// switchMap vs mergeMap taqqoslash
of('a', 'ab', 'abc').pipe(
mergeMap((term) => this.api.search(term).pipe(delay(Math.random() * 1000)))
// "a" uchun javob "abc" dan keyin kelishi mumkin — noto'g'ri UI
);
Imtihonda
- mergeMap va switchMap farqi — qaysi biri parallel, qaysi biri eskini bekor qiladi?
- 10 ta ID bo'yicha user olish kerak — mergeMap yoki concatMap?
Yodlash uchun
mergeMap = parallel, bekor yo'q. Mustaqil so'rovlar, upload, batch fetch.
concatMap — tartibli (queue)
Nima bu?
concatMap — ichki Observable'larni navbat (queue) bo'yicha ketma-ket bajaradi. Oldingi tugamasdan keyingisi boshlanmaydi. Tartib muhim bo'lgan operatsiyalar: navbat bilan yozish, ketma-ket API chaqiruvlar, birin-ketin fayl yuklash. mergeMap parallel, concatMap — bittasi tugagach keyingisi.
Kod misoli
import { from, of } from 'rxjs';
import { concatMap, delay, tap } from 'rxjs/operators';
// Ketma-ket yozish — tartib buzilmasin
const actions = [
{ type: 'CREATE', payload: { name: 'Order 1' } },
{ type: 'UPDATE', payload: { id: 1, status: 'paid' } },
{ type: 'DELETE', payload: { id: 1 } },
];
from(actions).pipe(
concatMap((action) =>
this.api.dispatch(action).pipe(
tap(() => console.log('Bajarildi:', action.type))
)
)
).subscribe();
// mergeMap bilan taqqoslash
of(1, 2, 3).pipe(
concatMap((n) => of(n).pipe(delay(1000 - n * 100)))
// Chiqish: 1 (1s), 2 (1.9s), 3 (2.8s) — ketma-ket
);
of(1, 2, 3).pipe(
mergeMap((n) => of(n).pipe(delay(1000 - n * 100)))
// Chiqish: 3, 2, 1 — parallel, tezroq tugaydi lekin tartibsiz
);
Imtihonda
- concatMap va mergeMap qachon tanlanadi?
- Payment → confirmation → email ketma-ket bo'lishi kerak — qaysi operator?
Yodlash uchun
concatMap = navbat, tartib saqlanadi. Queue, ketma-ket API, write operations.
exhaustMap — hozirgi tugamaguncha yangi qabul qilma (login)
Nima bu?
exhaustMap — ichki Observable hali tugamagan bo'lsa, yangi tashqi qiymatlarni e'tiborsiz qoldiradi. Faqat hozirgi operatsiya tugagach keyingisi qabul qilinadi. Login button spam, submit double-click, checkout — foydalanuvchi bir necha marta bosganda duplicate so'rov oldini oladi.
Kod misoli
import { Component } from '@angular/core';
import { fromEvent } from 'rxjs';
import { exhaustMap, tap, finalize } from 'rxjs/operators';
@Component({
template: `
<button #loginBtn [disabled]="loading">Kirish</button>
`,
})
export class LoginComponent {
@ViewChild('loginBtn') loginBtn!: ElementRef<HTMLButtonElement>;
loading = false;
ngAfterViewInit() {
fromEvent(this.loginBtn.nativeElement, 'click')
.pipe(
exhaustMap(() => {
this.loading = true;
return this.auth.login(this.credentials).pipe(
finalize(() => (this.loading = false))
);
})
)
.subscribe({
next: () => this.router.navigate(['/dashboard']),
error: (err) => (this.error = err.message),
});
}
}
// switchMap vs exhaustMap login'da:
// switchMap: har click eski login'ni bekor qiladi — noto'g'ri
// exhaustMap: birinchi login tugaguncha qolgan click'lar ignore — ✅
// mergeMap: har click alohida login — duplicate token xavfi
Imtihonda
- Login button uchun nima uchun exhaustMap, switchMap emas?
- To'rtta operator taqqoslang: switchMap, mergeMap, concatMap, exhaustMap.
Yodlash uchun
| Operator | Xulq | Misol |
|---|---|---|
| switchMap | Yangi → eski bekor | Search |
| mergeMap | Parallel | Batch fetch |
| concatMap | Navbat | Ketma-ket write |
| exhaustMap | Busy → ignore | Login, submit |
