RxJS更新状态和直通

时间:2018-12-03 14:51:13

标签: angular rxjs ngrx angular-httpclient

我有一个用户库,可在组织中的多个Angular应用程序中使用。作为重构/新版本,我们正在寻求一种基于状态的服务,其界面应如下所示:

export interface UserService {
    user: Observable<User>
    getProfile(url: string): Observable<User>
    updateProfile(url: string): Observable<User>
}

这样,消费者就可以将组件绑定到UserService.user,而知道数据将始终是最新的,并可以在按钮或后台活动等中调用get / update函数。

说明:该用户库适用于使用ngRx的应用程序,以及不希望使用较重功能但仍希望基于可观察的用户绑定的应用程序

所以我连接了这样的功能(略有变化):

public getProfile(url: string): Observable<User> {
    const obs = this._http.get<User>(url);
    obs.subscribe(profile => this.setProfile(profile));
    return obs;
}

setProfile更新UserService.user以只读方式返回的内部订阅的位置。

我的消费类应用程序一旦将ngRx用于其余的状态管理。使用我的图书馆时,我们注意到一些奇怪之处:<​​/ p>

  1. 当包装在ngRx效果中时,有时会多次调用使用Angular的HttpClient的任何函数。为了解决此问题,我使用HttpClient的任何函数都以.publishLast().refCount()结尾,以确保HTTP调用仅进行一次。

  2. 如果呼叫失败,则使用者无法捕获该异常。例如,this.authService.getProfile().catch(error => alert(error))将永远不会被调用。为了解决这个问题,我现在在我的订阅上修改我的函数:obs.subscribe(profile => this.setProfile(profile), error => Observable.throw(error));

在Angular中实现“状态存储”服务时,这是正常现象吗?

编辑: ngRx效果示例(请注意,这是真实的实现,我在上面发布的内容与我们的实际实现相比有所简化):

public BiographyUpdate: Observable<any> = this._actions.pipe(
    ofType(AuthActionTypes.BIOGRAPHY_UPDATE),
    map((action: BiographyUpdate) => action.payload),
    switchMap(bio => this._auth.update(`${Environment.Endpoints.Users}/users/sync/biography`, action)
      .map(profile => new BiographyUpdateSuccess(profile.biography))
      .catch(error => {
        console.log("AM I BEING HIT?");
        return Observable.of(new BiographyUpdateFailure(error.toString()))
      })
    )
  );

1 个答案:

答案 0 :(得分:1)

一旦调用subscribe事件,该事件就会被触发,并且subscribe方法中的结果将被解析(正确的结果或错误)。因此,此时,您调用this.authService.getProfile().catch方法,异步事件已被触发并结束。这就是为什么它不打电话。

您可以在catch中移动getProfile运算符,也可以不订阅而从getProfile返回可观测值。

public getProfile(url: string): Observable<User> {
    return this._http.get<User>(url)
            .pipe( tap( profile => this.setProfile(profile))); 
}

现在通过authService服务对其进行订阅

this.authService.getProfile()
  .subscribe(profile =>  // do the work)
  .catch(error => alert(error))