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