IF / ELSE IF / ELSE с наблюдаемым условным условием - PullRequest
0 голосов
/ 07 февраля 2019

Я пытаюсь создать метод для возврата настройки, которая может быть сохранена в одном из трех мест.Я создал три наблюдаемых, каждая из которых пытается получить значение настройки из источника.Я хотел бы иметь возможность «объединить» их таким образом, чтобы создать конструкцию IF / ELSE IF / ELSE, чтобы только один из Observables выдавал значение настройки в конце.Условие для перехода от одного наблюдаемого к следующему состоит в том, что предыдущий «потерпел неудачу», то есть испустил значение, которое не прошло условие.Порядок, в котором пробуется каждая опция, важен.

Итак, мой метод выглядит примерно так:

getSetting(settingName: string): Observable<any> {

    const optionOne$ = this.getItemAtFirst(settingName).pipe(
        take(1),
        filter(setting => setting && this.isSettingValid(settingName, setting)));

    const optionTwo$ = this.getItemAtSecond().pipe(
        take(1),
        filter(setting => setting && this.isSettingValid(settingName, setting)));

    const optionThree$ = of(this.defaultSettingValue);

    return merge(optionOne$, optionTwo$, optionThree$);
}

Это, очевидно, не работает, потому что merge не обеспечивает нужный эффект выбора.

Какие-либо предложения?Заранее спасибо!

Ответы [ 2 ]

0 голосов
/ 07 февраля 2019

РЕДАКТИРОВАТЬ: TL; DR

Заменить merge на concat и добавить first в трубу на concat:

concat(optionOne$, optionTwo$, optionThree$)
    .pipe(
        first()
    );

concat подписывается последовательно на каждое наблюдаемое, что означает, что optionOne$ подписывается первым, он выдает свои значения, по завершении отписывается от, затем concat подписывается на optionTwo$ и так далее ...пока все наблюдаемые не завершатся, а затем, наконец, не выдаст все значения в виде массива.Добавление first просто обрезает этот процесс, так как он завершает concat после первого испущенного значения.

Вам действительно нужно проверить, что все наблюдаемые внутри concat завершатся, или вы можете получитьусловие, при котором один из них никогда не генерируется или не завершается, и это будет означать, что вы никогда не получите значение, полученное из concat.

—-

Предполагая, что ваш isSettingValid() возвращает false, если он не проходит проверку, тогда просто добавьте pipe() с first() к concat().См. Немного измененную версию ниже, и stackblitz здесь.

Эта статья также информативна.И я предлагаю статью , в которой есть классные картинки для объяснения операторов и их работы - я всегда возвращаюсь к этому, когда пытаюсь понять что-то подобное.

Я думаю, что это отвечает на ваш вопрос, потому что он выдает первое значение, которое проходит проверку и игнорирует остальные.

import { of, Observable,  concat } from 'rxjs';
import { take, filter, first } from 'rxjs/operators';

function isSettingValid(setting): boolean {
  return setting !== 'error' ? true : false;
}

function getSetting(): Observable<any> {

  const optionOne$ = of('error')
    .pipe(
      take(1),
      filter(setting => isSettingValid(setting))
    );

  const optionTwo$ = of('second')
    .pipe(
      take(1),
      filter(setting => isSettingValid(setting))
    );

  const optionThree$ = of('default').pipe(
    take(1),
    filter(setting => isSettingValid(setting))
  );

  return concat(optionOne$, optionTwo$, optionThree$)
    .pipe(
      first() // emits only the first value which passes validation then completes
    );
}

getSetting()
  .subscribe((setting) => {
    console.log(setting);
  })

Я также предлагаю удалить setting &&, как в моем фрагменте,и установка нулевой проверки внутри вашей функции проверки - это просто делает фильтр более легким для чтения, если вы делаете это таким образом, imo.Чтобы сделать его более кратким, вы можете рассмотреть замену take(1) и filter() на first и функцию предиката, которая будет иметь тот же результат:

const optionOne$ = of('error')
    .pipe(
      first(setting => isSettingValid(setting))
    );
0 голосов
/ 07 февраля 2019

Это должно быть реализовано как цепочка.С помощью приведенного выше кода, даже несмотря на то, что вы извлекаете данные из IndexDB, вы все равно в конечном итоге будете вызывать MangoDB (в ожидании данных).Вместо того, чтобы усложнять, я делаю цепочку вызовов.Но все зависит от варианта использования.В этом случае, я думаю, цепочка вызовов будет лучше, используя оператор flatMap .

...