Current Behavior
shareReplay doesn't restart due to unsubscriptions when refCount is true if the source completes before the subscribers.
Reproduction
import {interval} from 'rxjs';
import {finalize, shareReplay, take} from 'rxjs/operators'
const sharedSource = interval(100).pipe(
take(5),
finalize(() => {
console.log('The source has completed!')
}),
shareReplay({refCount: true, bufferSize: 1}),
);
const s1 = sharedSource.subscribe(x => console.log('subscription 1', x));
const s2 = sharedSource.subscribe(x => console.log('subscription 2', x));
console.log('Two active subscriptions...')
setTimeout(() => {
s1.unsubscribe();
s2.unsubscribe();
console.log('Both subscriptions have been unsubscribed (refCount === 0)')
}, 550)
setTimeout(() => {
console.log('Creating a new subscription...')
sharedSource.subscribe(x => console.log('subscription 3', x))
}, 600)
Expected behavior
I would expect to restart the subscription to the source after the refCount has gone down to zero.
Environment
What you are seeing is the expected behaviour. Once the source completes, that's it. The completion is replayed. If you don't want this behaviour, use share instead.
Hi @cartant and thanks for your quick reply.
What you are seeing is the expected behaviour. Once the source completes, that's it. The completion is replayed. If you don't want this behaviour, use share instead.
I _really_ thought that this was a bug. Please notice that in the PR that I've opened all the existing tests are passing and I also added a new one to cover this case.
One of the reasons why I thought that this was a bug is that currently there is a test for shareReplay that states:
should restart due to unsubscriptions if refCount is true
I don't understand why that shouldn't be the case if the source has completed and all the subscribers have unsubscribed. I thought that was the point of using refCount. If that's not the expected behavior perhaps would it be worth it to add a test that makes sure that once the source has completed then the refCount is ignored?
Also, I know how to create my own operator with this behavior, but is there a way that I can get this behavior using share or publishReplay... because I can't think of a way to get that.
Thanks a lot for looking into this.
I don't understand why that shouldn't be the case ...
Look at it this way: if it resubscribes to the source it is not replaying the notifications.
I do understand what you are saying, but another way to look at it could be: when using refCount: true, then if the refCount goes down to zero then it's like nothing ever happened :smile:.
I'm not saying that you are wrong. I'm just saying that's what I expected/wished and when I found a test that seemed to state that, then that lead me to think that this was a bug. I also thought that if I wanted the behavior that you are describing as the expected one, then I could use:
source.pipe(publishReplay(1), refCount())
I thought that by having the refCount option in the shareReplay operator, then we would be able to get a behavior that's closer to the share operator...
Anyways, well, if it isn't a bug then 2 questions:
Thanks!
Would it be worth it to add a test that removes the current "ambiguity"?
Yes, definitely!
Is there a way to get the behavior that I was expecting by combining other lower-level operators?
Yes: multicast(() => ReplaySubject(1))
Thanks a lot! I'm going to get some rest now and I will send a PR with that test tomorrow. Once again: thanks a lot for being so responsive and supportive!
Most helpful comment
Yes, definitely!
Yes:
multicast(() => ReplaySubject(1))