网站搜索

javascript - 在 RxJS 管道中,有没有更简单、更优雅的方式处理 Observables?


想象一下,我有一个可观察对象会给我巧克力饼干,但我不想吃白色的饼干。不过因为我失明了,我必须把它们交给一个服务,以确定某个饼干是否是白色的。但我不会立即得到答案。我宁愿得到另一个可观察对象。

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

// 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);
}

虽然这确实可行且在某种程度上合理,但如果你必须在彼此之间嵌套更多这样的内容,就会变得非常混乱。有没有办法直接过滤 observable 或对其进行映射,以便在不使用那种奇怪的 combineLatest-of 组合的情况下获取我需要的信息?

答案#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);
  }

另外,请注意,你实际上不需要在变量名后附加 'Observable',因为你已经使用 $语法来表示该变量是一个 Observable。

答案#2

你可以在 switchMap 中使用 filter 来过滤掉白色饼干,然后将服务的响应映射回饼干

这是一个例子:

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);
})