Skip to content

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: switchMap replaces 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 catchError where it kills future interactions;
  • repeated signal/observable conversion;
  • imperative subscriptions without ownership/teardown;
  • unbounded mergeMap or stale shareReplay caches.

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

  1. Understand: next/error/complete and teardown.
  2. Apply: implement cancellable search.
  3. Analyze: locate accidental outer-stream termination.
  4. Evaluate: signal, BehaviorSubject, or observable for a given owner.
  5. 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.