WHITECOLOR WHITECOLOR - 14 days ago 6
Javascript Question

Rxjs get rid of double subscription

var sourceInit = Rx.Observable.timer(0, 1000)
.do(x => console.log('timer', x))

let source = sourceInit.map(x => x*10)

source.subscribe(x => {
console.log('x', x)
})

source.subscribe(x => {
console.log('x2', x)
})


The outpu I've got:

timer 0
x 0
timer 0
x2 0
timer 1
x 10
timer 1
x2 10
timer 2
x2 20
timer 2


I need have only single subscription to timer and output like this:

timer 0
x 0
x2 0
timer 1
x 10
x2 10
timer 2
x 20
x2 20


What is the correct approach to this problem should be?

I got with this approach using subject:

var sourceInit = Rx.Observable.timer(0, 1000)
.do(x => console.log('timer', x))

var source = new Rx.Subject();
sourceInit.subscribe(source)

source.subscribe(x => {
console.log('x', x)
})

source.subscribe(x => {
console.log('x2', x)
})


Is it correct and only one?

Answer

The double subscription issue you are experience has to do with the cold vs. hot nature of Rx observables. Observables are cold by default, so anytime you subscribe to them, you start from the beginning. You can find a detailed explanation of what is happening here : Hot and Cold observables : are there 'hot' and 'cold' operators?. This was made with Rxjs V4 in mind, but it should apply to Rxjs V5 too.

A common solution is to make the observable you want to subscribe to several times 'hot' (subjects are hot, so your solution works). That said, there is no need to use subjects here. To make a cold source hot, you can use a set of operators, share being the more common :

var sourceInit$ = Rx.Observable.timer(0, 1000)
       .share()
       .do(x => console.log('timer', x))

let source$ = sourceInit$.map(x => x*10)

source$.subscribe(x => {
    console.log('x', x)
})

source$.subscribe(x => {
    console.log('x2', x)
})
Comments