RxJS管道中是否存在一个更简单,更优雅的Observable解决方案?

时间:2019-04-09 14:41:25

标签: javascript angular typescript rxjs

想象一下,我可以给我巧克力饼干,但是我不想吃白色的。但是由于我是盲人,所以我必须将它们交给服务,以查找给定的cookie是否为白色。但是我没有立即得到答案。我宁愿再观察一个。

这是我想出的代码,但是我真的不喜欢它,我认为应该有一个更简单,更优雅的解决方案:

// pipe the observable
chocolateCookieObservable$.pipe(
  // use a switchMap to create a new stream containing combineLatest which combines...
  switchMap((chocolateCookie: ChocolateCookie) => combineLatest(
    // an artificially created stream with exactly one cookie...
    of(chocolateCookie),
    // and the answer (also an observable) of my cookie service
    this.chocolateCookieService
      .isChocolateCookieWithWhiteChocolate(chocolateCookie),
    // so I get an observable to an array containing those two things
  )),
  // filtering the resulting observable array by the information contained in 
  // the array (is the cookie white)?
  filter(([chocolateCookie, isWhite]: [ChocolateCookie, boolean]) => !isWhite),
  // mapping the array so that I can throw away the boolean again, ending up 
  // with only the now filtered cookies and nothing more
  map(([chocolateCookie]: [ChocolateCookie, boolean]) => chocolateCookie),
).subscribe((chocolateCookie: ChocolateCookie) => {
  this.eat(chocolateCookie);
}

尽管这确实可行并且在一定程度上是合理的,但是如果您必须将更多的封装在一起,这确实会造成极大的混乱。没有任何方法可以直接过滤可观察对象或对其进行映射,以便我无需使用奇怪的CombineLatest-of组合即可获取所需的信息?

2 个答案:

答案 0 :(得分:1)

您可以在filter内使用switchMap来过滤出白色Cookie,然后将响应从服务映射回Cookie

这里有个例子:

chocolateCookieObservable$.pipe(
  switchMap((chocolateCookie: ChocolateCookie) =>
    // async test if its white
    this.chocolateCookieService
      .isChocolateCookieWithWhiteChocolate(chocolateCookie)
      .pipe(
        // filter out white cookies
        filter(isWhite => !isWhite),
        // map back from isWhite to the cookie
        mapTo(chocolateCookie)
      )
  )
).subscribe((chocolateCookie: ChocolateCookie) => {
  // mmm, cookies!!!
  this.eat(chocolateCookie);
})

答案 1 :(得分:1)

您应该将此细分为多个语句。

以这种方式工作,将使您在使用Observables实现复杂的异步工作流时,可以生成更具可读性,可维护性的代码。

重构后,您的代码将如下所示:

const isWhite$ = chocolateCookie$.pipe(
    switchMap((chocolateCookie: ChocolateCookie) => this.chocolateCookieService.isChocolateCookieWithWhiteChocolate(chocolateCookie)),
);

chocolateCookie$.pipe(
    withLatestFrom(isWhite$),
    filter(([chocolateCookie, isWhite]: [ChocolateCookie, boolean]) => !isWhite),
    map(([chocolateCookie]: [ChocolateCookie, boolean]) => chocolateCookie),
  ).subscribe((chocolateCookie: ChocolateCookie) => {
    this.eat(chocolateCookie);
  }

另外,请注意,您实际上并不需要在变量名称的末尾附加“可观察的”,因为您已经在使用$语法表示变量是可观察的。