RXJS 我如何在另一个中使用一个可观察结果(然后一起处理这两个结果)
RXJS How do I use the result of one observable in another (and then process those two results together)
使用 RxJs 时一个非常常见的问题似乎是想要一个或多个可观察对象的结果然后在后续的结果中使用它们。
例如在伪代码中(故意不是 rx 或有效的 js 语法)
var someResult = $observable-A; // wait to complete
var finalResult = $observable-B(someResult.aValueINeed);
这可以通过一种丑陋的方式来完成,您可以订阅两者并在另一个内部调用一个。但是,这非常混乱并且不会给您太多灵活性。
例如(真正的语法)
$observable-A.subscribe(resultA => {
$observable-B(resultA.aValueINeed)
.subscribe(resultB => {
console.log('After everything completes: ', resultB);
}
}
这也意味着当您完成两个可观察对象时,没有其他任何东西可以轻易地消耗此流。
我的具体用例要求如下:
- 获取 $observable-A 的初始调用,因为它不需要任何其他东西(这是一个基本的 http GET 调用)
- 对另一个服务的 http GET 调用需要来自 $observable-A 的数据,returns $observable-B
- 使用两个可观察结果 (A + B) 为我的服务(在我的例子中,一个 Angular 服务)创建一个对象到 return 一个列表。
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.
Snorre Danielsen nailed this problem and full credit for this solution goes to him. I'd recommend having a look at this.
rxjs 运算符的伟大之处在于它们的互操作性。您可以混合搭配几乎所有东西以获得您想要的结果。
简而言之。这个问题的答案代码如下,我会进一步解释。
$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
(或别名 flatMap
)将可观察对象作为输入并将其投影(就像常规地图函数一样)。这意味着我们可以将其结果用作 $observable-B
的输入。现在,当您实际上只想 return 第二个可观察结果时,这非常有用。例如
$observable-A.pipe(
mergeMap(resultA => $observable-B(resultA)),
map((resultB) => {
// resultA doesn't exist here and we can only manipulate resultB
}
)
现在,回到主要解决方案。 combineLatest
是这里的关键。它允许 mergeMap
本质上 "wait" 来完成内部可观察对象 ($observable-B
)。
没有它,您将 return 一个可观察到 pipe
中的下一个 rxjs 运算符,这不是我们想要的(因为您期望在 [= 中处理常规运算符函数=18=]).
正因为如此,我们可以将这些新合并的可观察对象带入链的下一部分并一起使用。我们使用 of()
函数重新创建 resultA
,因为 combineLatest
仅将 observable 作为输入,而 resultA
是此状态下已完成的 observable。
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.
使用 RxJs 时一个非常常见的问题似乎是想要一个或多个可观察对象的结果然后在后续的结果中使用它们。
例如在伪代码中(故意不是 rx 或有效的 js 语法)
var someResult = $observable-A; // wait to complete
var finalResult = $observable-B(someResult.aValueINeed);
这可以通过一种丑陋的方式来完成,您可以订阅两者并在另一个内部调用一个。但是,这非常混乱并且不会给您太多灵活性。
例如(真正的语法)
$observable-A.subscribe(resultA => {
$observable-B(resultA.aValueINeed)
.subscribe(resultB => {
console.log('After everything completes: ', resultB);
}
}
这也意味着当您完成两个可观察对象时,没有其他任何东西可以轻易地消耗此流。
我的具体用例要求如下:
- 获取 $observable-A 的初始调用,因为它不需要任何其他东西(这是一个基本的 http GET 调用)
- 对另一个服务的 http GET 调用需要来自 $observable-A 的数据,returns $observable-B
- 使用两个可观察结果 (A + B) 为我的服务(在我的例子中,一个 Angular 服务)创建一个对象到 return 一个列表。
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.
Snorre Danielsen nailed this problem and full credit for this solution goes to him. I'd recommend having a look at this.
rxjs 运算符的伟大之处在于它们的互操作性。您可以混合搭配几乎所有东西以获得您想要的结果。
简而言之。这个问题的答案代码如下,我会进一步解释。
$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
(或别名 flatMap
)将可观察对象作为输入并将其投影(就像常规地图函数一样)。这意味着我们可以将其结果用作 $observable-B
的输入。现在,当您实际上只想 return 第二个可观察结果时,这非常有用。例如
$observable-A.pipe(
mergeMap(resultA => $observable-B(resultA)),
map((resultB) => {
// resultA doesn't exist here and we can only manipulate resultB
}
)
现在,回到主要解决方案。 combineLatest
是这里的关键。它允许 mergeMap
本质上 "wait" 来完成内部可观察对象 ($observable-B
)。
没有它,您将 return 一个可观察到 pipe
中的下一个 rxjs 运算符,这不是我们想要的(因为您期望在 [= 中处理常规运算符函数=18=]).
正因为如此,我们可以将这些新合并的可观察对象带入链的下一部分并一起使用。我们使用 of()
函数重新创建 resultA
,因为 combineLatest
仅将 observable 作为输入,而 resultA
是此状态下已完成的 observable。
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.