Advanced
Ilg'or RxJS mavzulari — custom operator yozish, Scheduler va marble testing. Senior intervyu va murakkab stream debug uchun.
Custom operator yaratish
Nima bu?
Custom operator — (source: ObservableT) => ObservableR`` qaytaradigan funksiya. Mavjud operatorlar yetmasa yoki loyiha bo'ylab takrorlanadigan logikani (loading flag, audit log) bir joyga jamlash uchun. pipe() ichida ishlatiladi, tap, map, catchError kombinatsiyasi sifatida yoziladi.
Kod misoli
import { Observable, OperatorFunction, finalize, tap } from 'rxjs';
// Loading indicator operator
export function withLoading<T>(
setLoading: (loading: boolean) => void
): OperatorFunction<T, T> {
return (source) =>
source.pipe(
tap({
subscribe: () => setLoading(true),
finalize: () => setLoading(false),
})
);
}
// Audit log operator
export function auditAction<T>(actionName: string): OperatorFunction<T, T> {
return (source) =>
source.pipe(
tap({
next: (value) => console.log(`[${actionName}]`, value),
error: (err) => console.error(`[${actionName}] ERROR`, err),
})
);
}
// Ishlatish
this.http.get<User[]>('/api/users').pipe(
withLoading((v) => (this.loading = v)),
auditAction('FETCH_USERS'),
catchError((err) => of([]))
).subscribe((users) => (this.users = users));
Imtihonda
- Custom operator va oddiy helper function farqi?
- Operator ichida subscribe qilish kerakmi?
Yodlash uchun
Operator = source Observable qabul → yangi Observable qaytar. subscribe emas, pipe zanjiri.
Scheduler — animatsion frame, asinkron
Nima bu?
Scheduler — Observable qachon va qaysi execution context'da ishlayotganini boshqaradi. asyncScheduler (default), asapScheduler (microtask), animationFrameScheduler (requestAnimationFrame), queueScheduler (sinxron navbat). Test va animatsiya sync uchun muhim; production'da kam ishlatiladi.
Kod misoli
import { of, scheduled, animationFrameScheduler, asyncScheduler } from 'rxjs';
import { observeOn, subscribeOn } from 'rxjs/operators';
// animationFrameScheduler — DOM animatsiya bilan sync
scheduled(of(1, 2, 3), animationFrameScheduler).subscribe(console.log);
// observeOn — emit qilish vaqtini o'zgartirish
of(1, 2, 3).pipe(
observeOn(animationFrameScheduler)
).subscribe((v) => this.updateChart(v));
// subscribeOn — subscribe qayerda bo'lishi
of(1, 2, 3).pipe(
subscribeOn(asyncScheduler)
).subscribe(console.log);
Imtihonda
- animationFrameScheduler qachon kerak?
- observeOn va subscribeOn farqi?
Yodlash uchun
subscribeOn = qayerda subscribe; observeOn = qayerda emit. animationFrame = rAF sync.
Marble testing — TestScheduler
Nima bu?
Marble testing — vaqt oqimini vizual diagramma (-, |, #, (ab)) bilan ifodalash va TestScheduler bilan sinxron test qilish. setTimeout/interval kutmasdan operator zanjirini test qilish. RxJS operatorlar va custom pipe'larni unit test qilish uchun professional usul.
Kod misoli
import { TestScheduler } from 'rxjs/testing';
import { debounceTime, map } from 'rxjs/operators';
describe('searchDebounce', () => {
let scheduler: TestScheduler;
beforeEach(() => {
scheduler = new TestScheduler((actual, expected) => {
expect(actual).toEqual(expected);
});
});
it('debounceTime 300ms kutadi', () => {
scheduler.run(({ cold, expectObservable, flush }) => {
const input = 'a-b-c---|';
// 300ms kutish davri manba tugashidan (8 frame) ancha uzun bo'lgani
// uchun timer hech qachon o'zi ishga tushmaydi — debounceTime faqat
// manba complete bo'lganda kutilayotgan qiymatni darhol chiqaradi.
const expected = '--------(c|)';
const source$ = cold(input);
const result$ = source$.pipe(debounceTime(300, scheduler));
expectObservable(result$).toBe(expected);
});
});
it('map transform', () => {
scheduler.run(({ cold, expectObservable }) => {
const source$ = cold('1-2-3|');
const result$ = source$.pipe(map((x) => Number(x) * 10));
expectObservable(result$).toBe('10-20-30|');
});
});
});
Imtihonda
- Marble diagrammada
-,|,#nima anglatadi? - Nima uchun TestScheduler oddiy fakeAsync'dan yaxshi?
Yodlash uchun
- = 10ms frame; | = complete; # = error. TestScheduler = vaqtni qo'lda boshqarish.
