RXJS How do I use the result of one observable in another (and then process those two results together)

自闭症网瘾萝莉.ら 提交于 2020-06-27 16:37:11

问题


A very common problem when using RxJs seems to be to want the result of one or more observables to then use them in subsequent ones.

e.g. in pseudo-code (This is not rx or valid js syntax deliberately)

var someResult = $observable-A; // wait to complete
var finalResult = $observable-B(someResult.aValueINeed);

This can be done in an ugly way where you could subscribe to both and call one inside the other.. however, this is very messy and doesn't afford you much flexibility.

e.g. (real syntax)

$observable-A.subscribe(resultA => { 
    $observable-B(resultA.aValueINeed)
        .subscribe(resultB => { 
            console.log('After everything completes: ', resultB); 
        }
}

This also means that nothing else can easily consume this stream as you're completing both of the observables.

My specific use case requires the following:

  1. An initial call to get $observable-A as it doesn't require anything else (it's a basic http GET call)
  2. An http GET call to another service that requires data from $observable-A, which returns $observable-B
  3. Using both observable results (A + B) to create an object for my service (In my case, an Angular service) to return a single list.

I also need to be able to subscribe to this function inside my service, this is why going with the subscribe method above, won't work for me.


回答1:


Snorre Danielsen nailed this problem and full credit for this solution goes to him. I'd recommend having a look at this.

The great thing about rxjs operators is their interoperability. You can mix and match almost everything to get your desired outcome.

In short. The code answer to this question is below, and i'll explain it further.

$observable-A.pipe(
    mergeMap(resultA => {
        return combineLatest(
            of(resultA),
            $observable-B(resultA)
        )
    }),
    map(([resultA, resultB]) => {
        // you can do anything with both results here
        // we can also subscribe to this any number of times because we are doing all the processing with
        // pipes and not completing the observable
    }
)

mergeMap (or flatMap which is an alias) takes an observable as an input and projects it (just like a regular map function). This means we can use its result as the input for $observable-B. Now this is great for when you actually want to only return the second observable result. e.g.

$observable-A.pipe(
    mergeMap(resultA => $observable-B(resultA)),
    map((resultB) => {
        // resultA doesn't exist here and we can only manipulate resultB
    }
)

Now, back to the main solution. combineLatest is the key here. It allows the mergeMap to essentially "wait" for the internal observable ($observable-B) to complete. Without it, you're just going to return an observable to your next rxjs operator in the pipe, which is not what we want (as you're expecting to deal with regular operator functions inside a pipe).

Because of this, we can take these new merged observables into the next part of the chain and use them together. We use the of() function to re-create resultA, as combineLatest only takes observables as inputs and resultA is a completed observable in this state.

A hint: Take a look at the map(([resultA, resultB]). The reason we use this notation to refer to our variables instead of the standard map(results). Is so we can directly reference them without using results[0] for resultA or results[1] for resultB. Its just a lot easier to read this way.


I hope this helps people out as I have yet to find a complete SO answer which covers this case. Edits are very welcome as its complicated and I'm sure its not a perfect answer.



来源:https://stackoverflow.com/questions/62141648/rxjs-how-do-i-use-the-result-of-one-observable-in-another-and-then-process-thos

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!