Функция конвейера RxJS без учета наблюдаемого

Я обновляю приложение до RxJS из Promises, и я не совсем уверен, на правильном ли я пути.

Случай: задан ModalComponant, который загружается при отправке HTTP-запроса и уничтожается при получении ответа. Итак, я делаю следующее

public post(uri: string, body: object, showLoading: boolean = true, params: object = {}): Observable<any> {
if (showLoading) {
  this.toggleModal('open');
}

return this.http.post(
  this.createUrl(uri),
  body,
  this.createOptionsWrapper(params)
)
.pipe(
  this.toggleModal('close'),
  catchError(err => this.handleError(err))
);

}

toggleModal () принимает 1 параметр и на его основе открывает / закрывает модальное окно. Я понимаю, что конвейерные операторы должны возвращать тип OperatorFunction. Как вы считаете, какой оператор RxJS наиболее подходит для вышеприведенного случая, когда я не касаюсь самого Observable, я просто хочу сделать его конвейерным, чтобы он работал в заданной последовательности? Может, стоит самому создать собственный? Конечно, возвращаемый здесь Observable будет снова передан по конвейеру, где бы ни был введен сервис.


person winnergo    schedule 15.04.2021    source источник
comment
На веб-сайте rxjs есть интерактивное дерево решений оператора. У меня есть одна наблюдаемая - ›когда она завершается, возникают ошибки или отписываются, я хочу выполнить функцию, которая приводит вас к finalize   -  person chrisbajorin    schedule 15.04.2021


Ответы (3)


Здесь лучше всего подойдет оператор IMO finalize. Он вызывается, когда источник завершается или возникает ошибка, и не будет изменять излучение наблюдаемого объекта.

public post(
  uri: string, 
  body: object, 
  showLoading: boolean = true,
  params: object = {}
): Observable<any> {
  if (showLoading) {
    this.toggleModal('open');
  }

  return this.http.post(
    this.createUrl(uri),
    body,
    this.createOptionsWrapper(params)
  ).pipe(
    finalize(() => {
      if (showLoading) {
        this.toggleModal('close');
      }
    }),
    catchError(err => this.handleError(err))
  );
}
person Michael D    schedule 15.04.2021
comment
согласны с тем, что finalize является правильным, но также следует заключить это в defer - person bryan60; 15.04.2021
comment
@ bryan60: Будет ли это иметь большое значение, учитывая, что HTTP-наблюдаемый холодный? - person Michael D; 15.04.2021
comment
Это имело бы значение, потому что строка toggleModal('open') появится до того, как наблюдаемый станет горячим, и если наблюдаемый никогда не станет горячим, то модальное окно никогда не закроется. - person bryan60; 15.04.2021
comment
спасибо, многому научился - person winnergo; 15.04.2021

@Michael D верен ИМО, что finalize является правильным оператором, но я также считаю, что вы должны заключить это в defer:

public post(uri: string, body: object, showLoading: boolean = true, params: object = {}): Observable<any> {
  return defer(() => {
    if (showLoading) {
      this.toggleModal('open');
    }

    return this.http.post(
      this.createUrl(uri),
      body,
      this.createOptionsWrapper(params)
    ).pipe(
      finalize(() => this.toggleModal('close')),
      catchError(err => this.handleError(err))
    );
  });
}

причина в том, что наблюдаемые ожидают, что они ничего не делают, если на них не подписаны. Итак, если вы просто создавали какое-то условное выражение, например:

let save$ = this.service.post(...)
if (id) {
   save$ = this.service.put(...)
}
save$.subscribe();

модальное окно не будет переключаться, пока вы на самом деле не подпишетесь. без defer модальное окно будет переключаться в строке 1. Основная идея заключается в том, что без defer вы создаете ситуации, когда модальное окно может открываться, а затем никогда не закрываться, если вы никогда не подписывались. использование defer гарантирует, что этого никогда не произойдет.

person bryan60    schedule 15.04.2021
comment
Да, в этом есть смысл. +1 - person Michael D; 15.04.2021

Используйте оператор tap, если вы не хотите изменять результаты ответа. .

return this.http.post(
  this.createUrl(uri),
  body,
  this.createOptionsWrapper(params)
)
.pipe(
      tap( () => this.toggleModal('close') ),
      catchError(err => this.handleError(err))
);
person Edward    schedule 15.04.2021