Reputation: 5539
I was trying to figure out RxJs. ShareReplay operator in particular. As per my understanding if there are two subscriptions to an observable then the observable should be executed twice. Unless there is a shareReplay involved. Obviously my understanding is incorrect because that is not what I is happening here. Could someone please help me understand this?
export class TestComponent implements OnInit {
constructor() {}
i = 0;
ngOnInit() {
console.clear();
let ob = this.httpcall().pipe(map(d => d));
let ob1$ = ob.pipe(map(d => d.toUpperCase()));
let ob2$ = ob.pipe(map(d => d.toLowerCase()));
ob1$.subscribe(d => {
console.log(d);
});
ob2$.subscribe(d => {
console.log(d);
});
}
httpcall() {
console.log("called");
this.i++;
return of("server cAlled:" + this.i);
}
}
Output:
called
SERVER CALLED:1
server called:1
The counter i did not get incremented to two even though there are two subscriptions and no shareReplay involved.
I was expecting(without shareReplay):
called
SERVER CALLED:1
called
server called:2
And with let ob = this.httpcall().pipe(map(d=>d),shareReplay());
I was expecting:
called
SERVER CALLED:1
server called:1
Upvotes: 2
Views: 329
Reputation: 2947
That is because httpcall()
is called only once via following line let ob = this.httpcall().pipe(map(d => d));
. So it means that Observable
that is returned by httpcall()
will be reused thereafter.
If thats clear, now think about ob
, which is source Observable. If you subscribe to this Observable you are going to get of("server cAlled:" + this.i);
where this.i = 1
. this.i
is only going to increase if method httpcall()
is executed once more, but it is not. Instead you are subscribing to the cold Observable ob
which will just print what was used to create it. The value of this.i
(which equals to 1) is already stored inside Observable ob
and it is not going to be changed until new instance is created, no matter how many times you subscribe to ob
.
Now lets look at the following code which is different:
let ob1$ = this.httpcall().pipe(map(d => d)).pipe(map(d => d.toUpperCase()));
let ob2$ = this.httpcall().pipe(map(d => d)).pipe(map(d => d.toLowerCase()));
In this situation httpcall()
is called twice, thus this.i++;
would happen twice and you would get what you were thinking to get.
Upvotes: 0
Reputation: 2824
it seems that of return observable of it's own, so it's body doesn't get executed twice, so i recreate the example to show the difference between normal observable and of
export class AppComponent implements OnInit {
constructor(
) {
}
i = 0;
ngOnInit() {
console.clear();
const ob = this.httpCall1();
const ob1$ = ob.pipe(map(d => d.toUpperCase()));
const ob2$ = ob.pipe(map(d => d.toLowerCase()));
ob1$.subscribe(d => {
console.log(d);
});
ob2$.subscribe(d => {
console.log(d);
});
this.i = 0;
const ob2 = this.httpCall2();
const ob3$ = ob2.pipe(map(d => d.toUpperCase()));
const ob4$ = ob2.pipe(map(d => d.toLowerCase()));
ob3$.subscribe(d => {
console.log(d);
});
ob4$.subscribe(d => {
console.log(d);
});
}
httpCall1() {
return of('server1 called:' + ++this.i).pipe(
tap(d => console.log('tap1', d)),
);
}
httpCall2() {
return new Observable<string>((observer) => {
this.i++;
observer.next('server2 called: ' + this.i);
observer.complete();
}).pipe(
tap(d => console.log('tap2', d)),
);
}
}
Upvotes: 0
Reputation: 84982
When you call subscribe, that will cause the observable to do everything it was defined to do. It was defined using of("server cAlled: 1");
, which is then passed into a map operator. So since you subscribed twice, of
will do its thing twice, and map
will do its thing twice.
You happened to create the observable inside a function named httpcall, but the observable doesn't know anything about httpcall. httpcall will not be invoked an additional time.
If you want the incrementing of this.i to be part of what happens when subscribing, then you may need to use Observable.create. For example:
httpcall() {
return Observable.create((observer) => {
this.i++;
observer.next("server called: " + this.i);
observer.complete();
})
}
Upvotes: 2