角度RXJS结构可观察

时间:2019-04-01 14:31:20

标签: angular rxjs observable

我有一个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 个答案:

答案 0 :(得分:1)

您可以使用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)));
    }
}

答案 1 :(得分:1)

使用Observables时,总是存在无法再传递Observable的边缘。在Angular中,它们可以传递到视图模板中,并通过| async管道进行订阅。或者,根据您的情况,返回canActivate的返回值。因此,在您的服务中使用Observables非常方便。

在服务中,如果要缓存结果,可以使用BehaviourSubject存储结果,然后将它们作为Observable传递给其他人。或者,您可以使用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订阅返回的observable。无需检查切换器是否已经加载-服务已经解决了这个问题。