Как сохранить наблюдаемое после ошибки в RxJS 6 и Angular 6

Может ли кто-нибудь помочь со сценарием, когда this._getReactions$.next() не работает всякий раз, когда this.http.get(...) получает ошибку. Я хочу сохранить наблюдаемое, чтобы принять следующий ввод.

private _getReactions$: Subject<any> = new Subject();

 constructor() {
  this._getReactions$
  .pipe(
    switchMap(() => {
        return this.http.get(...)
        // http request 
    }),
    catchError(error => {
      console.log(error);
      return empty();
    })
  )
  .subscribe(data => {
      console.log(data)
      //results handling
  });
 }

onClick() {
  this._getReactions$.next();
}


person Krishna    schedule 17.09.2018    source источник


Ответы (2)


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

что, если мы хотим жить.

защита основной цепочки наблюдателей — это решение
помещайте catch внутрь switchmap всякий раз, когда запускается запрос switchmap , создает наблюдаемый ajax, и на этот раз с catch.
switchmap имеет поведение, которое говорит, что мой источник еще не завершен, поэтому мне все равно, завершит ли ребенок, я буду продолжать.

 constructor() {
  this._getReactions$
    .pipe(tap(value => { this.loading = true; return value }),
      switchMap(() => {
        return this.http.get(...).pipe(
          catchError((error) => this.handleError(error)))
        // http request
      }),
    )
    .subscribe(data => {
      console.log(data)
      //results handling
      this.error = false;
      this.loading = false
    });
}

private handleError(error: HttpErrorResponse) {

  this.error = true;
  console.log(error)
  this.loading = false
  return empty();

Live Demo

Detailed Info

PS: вложение внутри любого оператора flattening, такого как mergeMap, concatMap, exhaustMap и других операторов выравнивания, также будет работать.

person Vikas    schedule 17.09.2018
comment
Спасибо за ваш ответ. Мне не удалось получить доступ к методу this.loading внутри метода handleError. Вы можете помочь мне с этим? ` private handleError (ошибка: HttpErrorResponse) { if (error.error instanceof ErrorEvent) { } else { this.loading = false; эта.ошибка = истина; } вернуть пустой(); }` - person Krishna; 17.09.2018
comment
@Krish, я также обновил свой ответ, а также stackblitz, пожалуйста, проверьте его :) - person Vikas; 17.09.2018
comment
Вы можете использовать механизм, показанный @Vikas, в вашем HttpInterceptor (HttpClient), чтобы избежать дублирования кода в ваших компонентах и/или службах. - person Lievno; 30.03.2020

Я нашел способ исправить это для всех запросов.

Создайте файл загрузчика, в котором будут выполняться все запросы

загрузчик.ts

import { Observable, Subject, Subscription, EMPTY } from 'rxjs';
import { catchError, map, switchMap } from 'rxjs/operators';

export class Loader<T1, T> {
  private _requestQueue: Subject<T1>;
  private _errorQueue: Subject<Error>;
  private _resultQueue: Observable<T>;
  private _loaded = false;

  constructor(loaderFunction: (T1) => Observable<T>) {
    this._requestQueue = new Subject<T1>();
    this._errorQueue = new Subject<Error>();
    this._resultQueue = this._requestQueue.pipe(
      switchMap(_ => {
        this._loaded = false;
        return loaderFunction(_).pipe(
          catchError(error => {
            this._loaded = true;
            this._errorQueue.next(error);
            // Returning EMPTY observable won't complete the stream
            return EMPTY;
          })
        );
      }),
      map(_ => {
        this._loaded = true;
        return _;
      }),
    );
  }

  public load(arg?: T1): void {
    this._requestQueue.next(arg);
  }

  public subscribe(successFn: (T) => any, errorFn?: (error: any) => void, 
    completeFn?: () => void): Subscription {
    
    this._errorQueue.subscribe(err => {
      errorFn(err);
    });
    return this._resultQueue.subscribe(successFn, null, completeFn);
  }

  public complete() {
    this._requestQueue.complete();
    this._errorQueue.complete();
  }
  
  get loaded(): boolean {
    return this._loaded;
  }
}

В других файлах, где вы будете выполнять запросы (просто)

export class Component {
  readonly loader: Loader<ResponseType, RequestParamType>;

  constructor() {
    this.loader = new Loader(param => this.http.get(param));
    this.loader.subscribe(res => {
      // Your stuffs
    }, (error) => { 
      // Error Handling stuffs
    }, () => {
      // on Complete stuffs (Optional)
    });
  }

  ngOnInit() {
    this.loadData();
  }

  loadData() { // Call this function whenever you want to refresh the data
    this.loader.load(params); // this param will directly passed to the http request
  }
}

Я определил другие параметры в загрузчике, которые могут помочь вам выбрать статус загрузки и возможность завершить поток (в ngOnDestroy)

Удачного кодирования!

person Bhavin    schedule 27.03.2021