#javascript #angular #typescript #rxjs
#javascript #angular #typescript #rxjs
Вопрос:
Представьте, что у меня есть observable, который дает мне шоколадное печенье, но я не хочу есть белое. Но поскольку я слепой, я должен передать их службе, чтобы узнать, является ли данный файл 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?
Ответ №1:
Вы должны разбить это на несколько операторов.
Работа таким образом позволит вам создавать более читаемый и поддерживаемый код при реализации сложных асинхронных рабочих процессов с наблюдаемыми объектами.
После рефакторинга ваш код будет выглядеть примерно так:
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’ в конец имени переменной, поскольку вы уже используете синтаксис $ для обозначения того, что переменная является наблюдаемой.
Ответ №2:
Вы могли бы использовать filter
inside of 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);
})