All topics
RxJSadvanced

Multicasting with share

Explain why a cold Observable re-executes its producer per subscriber, and how share/shareReplay makes it multicast instead.

By default, most Observables (an HTTP call via HttpClient, an Observable wrapping setTimeout) are "cold" — every single subscriber independently triggers the producer function from scratch, meaning two subscribers to the same http.get() Observable actually fire two separate HTTP requests, not one shared request whose result both subscribers see. This surprises many developers the first time they hit it, and it's a common source of accidental duplicate network requests in real applications, especially when an Observable is subscribed to in multiple places (like once in a template via the async pipe, and once more in the component class).

A cold Observable is like ordering an individually-cooked meal every time someone asks for one, even if ten people ask for the exact same dish at the exact same moment; share()/shareReplay() is like cooking one large batch and serving everyone from it, with shareReplay additionally keeping a warm plate ready for anyone who shows up a little late.

Key Concepts

1
share() (and its more specialized cousin, shareReplay()) converts a cold Observable into a multicast one: internally, it wraps the source with a Subject (or ReplaySubject, for shareReplay), subscribing to the actual source only once regardless of how many subscribers attach, and forwarding that single execution's emissions to everyone. shareReplay(1) additionally caches the most recent emission, so a subscriber joining after the value has already been emitted still receives it immediately, rather than needing to wait for a new emission (or missing it entirely) — extremely useful for caching an HTTP response that multiple components need without re-triggering the network call each time.
share()shareReplay()SubjectReplaySubjectshareReplay
2
An interview-relevant nuance around shareReplay involves reference counting: whether the underlying source stays subscribed after all downstream subscribers unsubscribe (potentially retaining a stale cached value and an idle subscription indefinitely) versus tearing down and resetting once the last subscriber leaves depends on the refCount configuration option, and getting this wrong is a documented, historically leaky default that RxJS's newer configurable shareReplay({ bufferSize, refCount }) signature was specifically introduced to address.
shareReplayrefCountshareReplay({ bufferSize, refCount })
3
A solid answer connects this back to the async pipe: subscribing to the same Observable via the async pipe in two different places in a template (or once in the template and once in the component) without sharing means duplicate execution, so shareReplay is the standard fix specifically for that pattern.
shareReplay