Lesson 9 — RxJS and temporal policy¶
Objective¶
Build cancellation-aware event pipelines and choose signals or observables by semantics rather than fashion.
Prerequisites¶
Signals, HTTP cold observables, async-state modeling, and pure transformations.
Mental model¶
An observable represents values over time with next, error, and completion channels. Operators create new streams. Higher-order mapping is a concurrency policy, not merely syntax.
Why it exists¶
Temporal systems need explicit cancellation, ordering, concurrency, retries, teardown, and composition—concerns a current synchronous value does not express alone.
Working model:
switchMapreplaces the old request with the new one.Engineering reality: unsubscription requests teardown; whether work truly cancels depends on the source. Error placement determines whether an inner operation fails or the outer interaction stream terminates.
Minimal example¶
| Operator | Policy | Typical use |
|---|---|---|
switchMap |
cancel previous | query reads |
concatMap |
queue in order | ordered writes |
exhaustMap |
ignore while active | duplicate-submit prevention |
mergeMap |
run concurrently | independent bounded work |
Real-world usage¶
Autocomplete, saves, uploads, websockets, polling, route events, and analytics require different temporal policies.
Common mistakes¶
- selecting operators from memorized recipes without naming policy;
- placing
catchErrorwhere it kills future interactions; - repeated signal/observable conversion;
- imperative subscriptions without ownership/teardown;
- unbounded
mergeMapor staleshareReplaycaches.
Mini lab¶
Task: Normalize, debounce, and deduplicate search input; map to repository search with explicit error state; bridge once with toSignal or AsyncPipe; use takeUntilDestroyed only for unavoidable imperative work.
Constraints: no nested subscriptions or real-time sleeps in tests; future searches must work after an error.
Expected result: equivalent queries deduplicate, stale reads cancel, and error recovery preserves the outer interaction stream.
Hint 1
State the desired concurrency sentence before choosing an operator.
Hint 2
Ask whether catchError should replace one request or terminate the user's search-event stream.
Solution direction — last resort
Put request error mapping inside switchMap, then bridge the resulting owned stream once at the template boundary.
Verification¶
Use virtual time or fake timers for debounce and cancellation. Move catchError outside switchMap, reproduce the dead search after failure, explain which stream terminated, then repair it.
Mastery evidence: derive operator choice from policy, prove cancellation/error behavior, and defend the signal bridge location.
Bloom challenge¶
- Understand: next/error/complete and teardown.
- Apply: implement cancellable search.
- Analyze: locate accidental outer-stream termination.
- Evaluate: signal,
BehaviorSubject, or observable for a given owner. - Create: design bounded, expiring request sharing with invalidation.
Summary¶
RxJS expresses time and concurrency. Operator and error boundaries encode product behavior.
Spaced review¶
Contrast derived signals from Lesson 4 with temporal streams. Lesson 10 tests time deterministically.
What comes next¶
Continue to testing and use Signals vs RxJS for decision rehearsal.