想象一下,我有一个可观察的给我巧克力饼干,但我不想吃白色的。但由于我是盲人,我必须将它们交给服务部门,以查明给定的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);
}
虽然这确实有效并且有些合理,但如果你必须将更多的内容封装在一起,那么它真的会变得非常混乱。有没有办法直接过滤observable或映射它,所以我得到了我需要的信息,而不使用那个奇怪的combineLatest组合?
您应该将其分解为多个语句。
以这种方式工作将允许您在使用Observable实现复杂的异步工作流时生成更易读,可维护的代码。
重构后,您的代码看起来像这样:
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。
您可以在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);
})