问题
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:
- An initial call to get $observable-A as it doesn't require anything else (it's a basic http GET call)
- An http GET call to another service that requires data from $observable-A, which returns $observable-B
- 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 standardmap(results)
. Is so we can directly reference them without usingresults[0]
forresultA
orresults[1]
forresultB
. 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