shareReplay vs ReplaySubject - only ReplaySubject caches latest value before subscription

Viewed 1839

I have an external hot source pushing values before observers can subscribe. Upon subscription, the late observers should receive the latest value and every value from that point on. For this, I used the following code (the relevant line is marked with '<<<', the s Subject is here just to be able to create the simplest sample possible, in reality the hot source works differently):

// irrelevant, just to send values
const s = new Subject();

// make the observable cache the last value
const o = s.pipe(shareReplay(1)); // <<<

// now, before subscription, values start coming in
s.next(1);
s.next(2);
s.next(3);

o.subscribe(n => console.warn('!!!', n));

This doesn't work (I expected it to print !!! 3 but nothing happens), but I found a way to make it work:

// irrelevant, just to send values
const s = new Subject();

const r = new ReplaySubject(1);
s.subscribe(r);
const o = r.asObservable();

s.next(1);
s.next(2);
s.next(3);

o.subscribe(n => console.warn('!!!', n));

i.e instead of using shareReplay(1), I create a ReplaySubject(1) and use it as a bridge. With this code, I do get the coveted !!! 3.

While I'm happy it works, I would like to understand why the first snippet doesn't. I always thought shareReplay is pretty much equivalent to the second way and actually kind of implemented this way. What am I missing?

1 Answers

When you use s.pipe(shareReplay(1)) you're just adding an operator to the chain (like changing the chain's prototype). But there's no subscription and shareReplay doesn't subscribe to its source when it itself doesn't have any observers. So it's not caching anything because there's no subscription to source Observable even when source is "hot".

However, when you use s.subscribe(r) you're regularly making a subscription to s so r starts receiving items and ReplaySubject will be caching them.

Related