Есть ли более простое и элегантное решение для наблюдаемых в каналах RxJS?

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