Угловые RXJS структурирующие наблюдаемые - PullRequest
0 голосов
/ 01 апреля 2019

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

охранник -

canActivate() {
   if(this.toggleService.hasToggles){
      return this.toggleService.isOn('my toggle');
   } else {
      return this.toggleService.getToggles().subscribe(() => {
         return this.toggleService.isOn('my toggle')
      })
   }
}

услуга -

@Injectable    
export class ToggleService {
       private _toggles: string[];
       private _hasToggles: boolean;

       getToggles() {
          return this.http.get('...').subscribe((toggles) => {
             this._toggles = toggles;
          })
       }

       isOn(toggle) {
          // return if toggle is in this._toggles;
       }
    }

Однако, поскольку внутри службы, на которую я уже подписываюсь, я возвращаю подписку, а не наблюдаемую. Я могу создать локальную ссылку на наблюдаемое в getToggles и вернуть его, но должен ли я использовать этот шаблон?

Ответы [ 2 ]

1 голос
/ 01 апреля 2019

При работе с Observables всегда есть грань, где вы не можете пройти дальше Observable. В Angular их можно передать в шаблон представления, подписавшись на них через канал | async. Или, в вашем случае, в качестве возвращаемого значения canActivate. Поэтому очень удобно использовать Observables в вашем сервисе.

В вашем сервисе, если вы хотите кэшировать результаты, вы можете сохранить их, используя BehaviourSubject, а затем передать их как наблюдаемые. Или вы можете создать наблюдаемый с оператором shareReplay и использовать его снова. Или просто вы можете просто сохранить их и вернуть их, используя функцию of из 'rxjs'. Я собираюсь проиллюстрировать последний вариант.

@Injectable    
export class ToggleService {
   private _toggles: string[];
   private _hasToggles: boolean;

   getToggles(refresh?: boolean) {
      if (!refresh || !this.toggles) {
      return this.http.get('...').pipe(
        tap((toggles) => {
         this._toggles = toggles;
        });
      );
      } else {
        return of(this._toggles);
      }

   }

Из isOn вы также можете вернуть Observable - boolean типа. Таким образом, вы можете пройти как можно дальше.

   isOn(toggle): Observable<boolean> {
      return this.getToggles().pipe(
        map(toggles => toggles.includes(toggle))
      )
   }

canActivate становится очень простым:

canActivate(): Observable<boolean> {
  return this.toggleService.isOn('my toggle');
}

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

1 голос
/ 01 апреля 2019

Вы можете использовать ReplaySubject для повторения последних отправленных значений для новых подписок, а затем getToggles() вызывать http.get() только один раз.

https://www.learnrxjs.io/subjects/replaysubject.html

@Injectable({providedIn: 'root'})
export class ToggleService {
    private _toggles: ReplaySubject<string[]>;

    getToggles(): ReplaySubject<string[]> {
        if (!this._toggles) {
            this._toggles = new ReplaySubject();
            this.http.get('...').subscribe((toggles) => this._toggles.next(toggles));
        }
        return this._toggles;
    }

    isOn(toggle): Observable<boolean> {
        return this.getToggles().pipe(map(toggles => toggles.includes(toggle)));
    }
}

Вы также можете использовать оператор shareReply:

https://www.learnrxjs.io/operators/multicasting/sharereplay.html

@Injectable({providedIn: 'root'})
export class ToggleService {
    private _toggles: Observable<string[]>;

    getToggles(): Observable<string[]> {
        if (!this._toggles) {
            this._toggles = this.http.get('...').pipe(shareReplay(1));
        }
        return this._toggles;
    }

    isOn(toggle): Observable<boolean> {
        return this.getToggles().pipe(map(toggles => toggles.includes(toggle)));
    }
}
...