当更新了不同的可观察值时,如何更新可观察值?

时间:2019-04-30 15:06:20

标签: angular typescript rxjs

我可以在Angular服务中使用一次性订阅http操作吗?这样做有什么缺点吗?

public async signInAsync(userName: string, password: string): Promise<void> {
    try {
      const token = await this.authenticate(userName, password).pipe(first()).toPromise();
      this.signInCompleted(token);
    } catch {
      this.signInFailed();
    }
  }

为了使用OnPush更改检测策略并在服务内部保留“业务逻辑”,服务使用称为state$的可观察的方式向组件公开值,然后组件通过异步管道订阅该值。只有服务功能才能通过调用this.patchState('actionName', {...})更新状态。

protected signInCompleted(token: string): void {
    this.localStorageService.setItem(LocalStorageKey.AUTH_TOKEN, token);
    this.patchState('signInCompleted', {
      isAuth: true,
      token: token,
      error: null
    });
    this.router.navigate([AppRoute.AUTH]);
  }

因此,如果我使用HttpClient,则必须以某种方式订阅返回的observable。

我从简单的订阅开始:

protected signIn(...): void {
    this.authenticate(..).subscribe(..);
}

但是后来,我意识到它是不可测试的,因为我不知道何时执行调用,并且async()不知道可观察性。 为了使其可测试,我必须使其异步并转换为Promise,但是我不确定如果我订阅pipe(first()).toPromise()是否有任何不利之处。

我也在考虑使用pipe(map(...)).pipe(catchError(...)),但是我不知道如何将操作绑定到组件,或者它是否比以前的方法更好。

  public signIn(userName: string, password: string): Observable<void> {
    return this.authenticate(userName, password).pipe(map(...)).pipe(catchError(...));
  }

1 个答案:

答案 0 :(得分:0)

使用promise似乎不是一个好方法,而当需要更新的请求或组件被破坏时,使用observables很容易取消调用。我不得不说语法没有像Promise中的async / await一样清晰,有时也很难测试,但是取消非常有用(特别是如果您在自动完成组件中有用于搜索的API调用绑定到每个击键和依此类推)。

对于副作用处理,我建议创建一个新的运算符:

export function effect<T>(
  completed?: (value: T) => void,
  failed?: (error: any) => void
): OperatorFunction<T, void> {
  return (observable$: Observable<T>): Observable<void> =>
    observable$.pipe(
      tap(completed, failed),
      catchError(_ => of()),
      map(() => {})
    );
}

在服务中使用它:

public login(userName: string, password: string): Observable<void> {
    return this.loginUsingPOST(userName, password).pipe(
      effect(
        token => this.loginCompleted(token),
        error => this.loginFailed(error)
      )
    );
  }

并仅订阅组件:

  public submit(): void {
    this.authService
      .login(this.loginForm.value.userName, this.loginForm.value.password)
      .pipe(this.untilDestroy())
      .subscribe();
  }

感谢@fridoo