2

New to Angular and RxJS, trying to understand this a bit... my app reacts to a UI event and that results in making a call out to a HTTP service that returns an Observable. I subscribe to it like so:

this.myXYZService.search(query)
  .map(r => { // some code })
  .subscribe(r => { //some code });

Say that event triggers again and it results in making a second call out to the same HTTP service that will return a brand new Observable BEFORE the 1st call finishes.

Now, as I understand it I can use switchMap instead of map to discard the old Observable and operate on the new Observable? Or am I understanding this incorrectly? And what happens if the second event triggers after the 1st event is already in the subscribe part of the chain? In this case it will no longer switch? And since JS is synchronous wouldn't the entire 1st chain execute anyway before the 2nd event even starts processing its chain?

I guess I am confused by the whole thing because the instances of the Observables are different - how does Rx keep track which call to switch?? Is it by the function name? Say I have 2 separate blocks of code:

this.myXYZService.search('abcd')
  .map(r => { // some code })
  .subscribe(r => { //some code });

this.myXYZService.search('efgh')
  .map(r => { // some code })
  .subscribe(r => { //some code });

if I use switchMap on both of the above what exactly happens? Does the second call cancel out the first?

Audwin Oyong
  • 2,247
  • 3
  • 15
  • 32
SBKDeveloper
  • 613
  • 1
  • 9
  • 20

2 Answers2

10

switchMap cancels the previous inner observable when the outer observable emits. For example

Observable.fromEvent(inputEl, 'keydown') // outer observable
    .switchMap(event => {
        let value = event.value;

        return this.myXYZService.search(value); // inner observable
    })
    .subscribe(res => {
        // some code
    });

In this case, every time the outer observable (fromEvent) emits (on keydown of input element), the inner observable (myXYZService.search) is called and the previous inner observable is cancelled.

LLai
  • 13,128
  • 3
  • 41
  • 45
  • Hi, just curious, it seems like with switchMap you'd likely want your subscribe argument to switch as your subscribed observable switches, because now you're dealing with potentially totally different values. How would someone handle this? Is there a way to indicate to your subscribe function which observable it's now subscribed to? – Esten Mar 21 '20 at 18:00
3

You would want something like...

searchTerms.switchMap( searchTerm => this.myXYZService.search(searchTerm) ).subscribe(...)

As soon as a new search term arrives then any in-progress search calls will be ignored / discarded. I wouldn't use the word cancelled because the call still goes out. However, their result will be ignored.

If the first request returns before the second search term is emitted then it will be sent to the subscription. If it doesn't then it will not.

Pace
  • 41,875
  • 13
  • 113
  • 156
  • Good call on the term `cancelled`. I think people often use this terminology because the networks tab says cancelled, when in reality the call still occurs, the client just stops listening. – LLai Dec 05 '17 at 19:35
  • thanks, so in this case searchTerms would be in the outer observable, that makes sense now. – SBKDeveloper Dec 05 '17 at 22:17
  • @Eliseo Here is a good [article](https://tolikcode.github.io/post/rxjsMap/) on switchMap vs flatMap vs concatMap. Technically all of these can be used to chain observables in sequence. But the inner observable reacts differently based on the operator. With switchMap, the previous inner observable is discarded when the outer observable emits. So in a sense, you are "switching" out the inner observable when a new one is created (when the outer observable emits) – LLai Dec 05 '17 at 23:04