javascript - ¿Existe una solución más fácil y elegante para los Observables dentro de las tuberías de RxJS?
Imagina que tengo un observable que me da galletas de chocolate, pero no quiero comer las blancas. Pero como soy ciego, tengo que entregarlas a un servicio para averiguar si una galleta dada es blanca o no. Pero no obtengo la respuesta de inmediato. Preferiría recibir otro observable.
Así que aquí está el código que se me ocurrió, pero realmente no me gusta y creo que debería haber una solución mucho más fácil y elegante para esto:
// 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);
}
Aunque esto funciona y es algo razonable, realmente se vuelve extremadamente confuso si tienes que encapsular más de esos dentro unos de otros. ¿No hay alguna manera de filtrar directamente el observable o mapearlo para obtener la información que necesito sin usar esa extraña combinación de combineLatest-of?
Respuesta #1
Deberías desglosar esto en varias declaraciones.
Trabajar de esta manera te permitirá producir código más legible y mantenible al implementar flujos de trabajo asincrónicos complejos con Observables.
Cuando se refactorice, tu código se vería algo así:
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);
}
Además, ten en cuenta que realmente no necesitas añadir 'Observable' al final del nombre de la variable, ya que ya estás usando la sintaxis $para indicar que la variable es un Observable.
Respuesta #2
Podrías usar filter dentro de switchMap para filtrar galletas blancas, y luego mapear la respuesta del servicio de vuelta a la galleta
Aquí hay un ejemplo:
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);
})
