Как обновить наблюдаемое значение, когда разные наблюдаемые были обновлены? - PullRequest
0 голосов
/ 30 апреля 2019

Можно ли использовать одноразовую подписку на действие http в службе Angular? Есть ли какой-либо недостаток в этом?

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, я должен каким-то образом подписаться на возвращаемое наблюдаемое.

Я начал с простой подписки:

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

Но потом я понял, что это не поддается тестированию, потому что я не знаю, когда выполняется вызов, а async() не знает о наблюдаемом. Чтобы он был тестируемым, мне нужно было сделать его асинхронным и преобразовать в обещание, однако я не уверен, есть ли какой-либо недостаток, если я подпишусь на 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 голосов
/ 08 мая 2019

Кажется, что использование обещаний не является хорошим подходом, в то время как использование наблюдаемых легко отменяет вызовы, когда требуется более новый запрос или компонент был уничтожен.Я должен сказать, что синтаксис не так понятен, как с 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...