rxjs异步更新为Observable

时间:2019-02-20 15:03:08

标签: rxjs reactive-programming rxjs6

在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 $的输出并对其应用异步更新,以记住过去的所有更新? (以一种我可以清除所有更改的方式)

1 个答案:

答案 0 :(得分:0)

因此,如果我提出的问题正确,那么这个问题将解决两个问题:

第一:如何缓存流中最后发出的2个值。

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)与将更改数据的异步可观察对象结合起来。