在使用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);
}
}
这也就意味着,在你完成这两个观测点的时候,没有任何其他东西可以轻易消耗这个流。
我的具体用例要求如下。
我还需要能够在我的服务内部订阅这个函数,这就是为什么用上面的订阅方法,对我来说是行不通的。
Snorre Danielsen解决了这个问题,这个解决方案的全部功劳归于他。我推荐你看看 这个.
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
. 现在,当你实际上只想返回第二个可观察的结果时,这是很好的选择,如
$observable-A.pipe(
mergeMap(resultA => $observable-B(resultA)),
map((resultB) => {
// resultA doesn't exist here and we can only manipulate resultB
}
)
现在,回到主要的解决方案。combineLatest
是这里的关键。它允许 mergeMap
基本上是 "等待 "内部的可观测数据($observable-B
)来完成.如果没有它,你只会返回一个观测值到你的下一个rxjs操作符中的 pipe
,这不是我们想要的(因为你期望在一个 pipe
).
正因为如此,我们可以将这些新合并的观测值带入链的下一部分,并一起使用它们。我们使用 of()
函数来重新创建 resultA
作为 combineLatest
只将观测值作为输入,并且 resultA
是这种状态下的一个完整的可观察对象。
一个提示:看一下
map(([resultA, resultB])
. 我们之所以用这个符号来表示我们的变量,而不是标准的map(results)
. 是为了让我们可以直接引用它们,而无需使用results[0]
对于resultA
或results[1]
对于resultB
. 它只是一个更容易阅读这种方式。
我希望这能帮助大家,因为我还没有找到一个完整的涵盖这个案例的SO答案。非常欢迎编辑,因为它的复杂性,我敢肯定它不是一个完美的答案。