Sang
Sang

Reputation: 4456

Second subscription to a shared mapping from BehaviorSubject does not execute

When I subscribe to a shared mapping from BehaviorSubject instance (t), only first subscription is executed.

When the original BehaviorSubject (obj) emits second value, only the latest value is printed, and both subscriptions were executed.

Let check my code

const obj = new Rx.BehaviorSubject(1)
obj.subscribe(console.log)
const t = obj.map(u => {
  console.log("mapped")
  return u * 10
}).share()

t.subscribe(x => console.log("subscribe 1 " + x))
t.subscribe(x => console.log("subscribe 2 " + x))
//with the following line un-commented, both subscriptions print out new value
//obj.next(2)

My expected result is

1
mapped
subscribe 1 10
subscribe 2 10

but the actual result was

1
mapped
subscribe 1 10

Sorry for the naive question. Is there anyone can explain this to me?

Thank you so much

Upvotes: 1

Views: 406

Answers (2)

martin
martin

Reputation: 96899

In your example you have two Subjects:

  • the BehaviorSubject in obj.

  • Subject instance inside .share().

Remember that BehaviorSubject emits its cached value only when you subscribe to it.

The first observer obj.subscribe(console.log) subscribes directly to the BehaviorSubject. This prints 1.

Then you create a chain t that ends with the share() operator.

Now you subscribe to t with t.subscribe. This means you subscribe to the Subject inside share() and since this is its first observer it needs to subscribe to its source Observable (which in turn reaches the source BehaviorSubject that emits its cached value). Note that share() is just a shortcut for using the multicast() operator with refCount().

And the last line you subscribe again with t.subscribe. Just like previously this subscribes to the Subject inside share(). However share() already is subscribed to its source Observable so it doesn't make another subscription. That's the point of multicasting and the multicast() operator.

That's why you won't see any subscribe 2 10 and you won't event see mapped printed twice. You're subscribing to the Subject inside share(), not the source BehaviorSubject.

Upvotes: 0

Olaf Horstmann
Olaf Horstmann

Reputation: 16892

Any operator (including the share) actually creates a new Sub-Observable, which has it's own share/replay-properties that are detached from the source-observable.

So to have your result, you should use publishReplay(1) instead of share(). (With publishReplay you of course have to either use refCount() or connect())

const obj = new Rx.BehaviorSubject(1)
obj.subscribe(console.log)
const t = obj.map(u => {
  console.log("mapped")
  return u * 10
}).publishReplay(1)
.refCount();

t.subscribe(x => console.log("subscribe 1 " + x))
t.subscribe(x => console.log("subscribe 2 " + x))
//with the following line un-commented, both subscriptions print out new value
//obj.next(2)
<script src="https://unpkg.com/rxjs/bundles/Rx.min.js"></script>

Upvotes: 1

Related Questions