在Observable流的中间处理异步更新的最佳方法是什么。
假设有3个可观察值:
Obs1(从API获取数据)->管道到Obs2 Obs2(转换数据)->管道到Obs3 Obs3(发送转换后的数据)
(实际的应用程序更复杂,并且有一个原因不能在一个Observable中完成,这只是一个简单的示例)。
如果它是线性同步路径,那么一切都很好。
但是我们还有异步消息,它将更改Obs2的输出。
我要问的3种情况是: -我们获取数据,然后通过Obs1,Obs2和Obs3 -通过Obs2和Obs3,我们收到一条进行更改的消息 -我们收到另一条消息进行更改,并且还需要通过Obs2&Obs3
应用上一条消息中的更改这里的主要问题是,有不同类型的异步消息会改变Obs2的结果,但是它们都必须仍然知道Obs2的先前结果是什么(因此,之前发生的消息的其他任何变化都是仍然适用)
我已经尝试在Obs2中使用switchMap并在Obs1中进行如下扫描:
obs1
const obs1$ = obs1$.pipe(
// this returns a function used in the reducer.
map((data) => (prevData) => 'modifiedData',
scan((data, reducer) => reducer(betsMap), {})
)
obs2
const obs2$ = obs1$.pipe(
switchMap(data =>
someChange$.pipe(map(reducer => reducer(data)))
)
)
其中someChange$
是一个BehaviorSubject,它使用另一个reducer函数来应用更改。
这对于进行一些更改的异步消息#1很好用。 但是,当出现消息2并需要进行其他更改时,第一个更改将丢失。
obs1 $的“ prevData”中的更改始终是未定义的,因为它发生在应用消息之前。
如何获取obs2 $的输出并对其应用异步更新,以记住过去的所有更新? (以一种我可以清除所有更改的方式)
答案 0 :(得分:0)
因此,如果我提出的问题正确,那么这个问题将解决两个问题:
scan
绝对是正确的方法,如果需要在多个位置/文件中使用此缓存逻辑,我将选择自定义管道运算符,例如以下代码
function cachePipe() {
return sourceObservable =>
sourceObservable.pipe(
scan((acc, cur) => {
return acc.length === 2 ? [...acc.slice(1), cur] : [...acc, cur];
}, [])
);
}
cachePipe
将始终返回通过流传递的最新2个值。
...
.pipe(
cachePipe()
)
在这里,rxjs的combineLatest
创建运算符可以为您解决问题,
combineLatest(API$, async1$ ,async2$,async3$)
.pipe(
// here I have access to an array of the last emitted value of all streams
// and the data can be passed to `Obs2` in your case
)
在pipe
中,我可以链接任意数量的可观察对象,从而解决了第二个问题。
combineLatest
对其中所有流的需求,以发射 一次,然后操作员开始散发< strong>合并值,一种解决方法是对输入流使用startWith
运算符,另一种方法是通过数据槽BehaviorSubject
-s。
这里是CodeSandbox处的演示,它使用cachePipe()
和startWith
策略将源(Obs1)与将更改数据的异步可观察对象结合起来。