簡體   English   中英

Angular2 異步管道的錯誤處理

[英]Error handling with Angular2 async pipe

我正在使用 Angular2 異步管道將值流式傳輸到 DOM 中。 這是一個非常簡單的例子:

const stream = Observable.interval(1000)
  .take(5)
  .map(n => { if (n === 3) throw "ERROR"; return n; });

<div *ngFor="for num of stream | async">
  {{num}}
</div>

<div id="error"></div>

我想要做的是顯示 1-5 的序列,但是在錯誤項 (3) 上,以某種方式用錯誤消息填充#error div。

這似乎需要兩件事:首先是 Angular 異步管道能夠用錯誤來做一些智能的事情,我看不到任何跡象。 查看源碼,顯然是拋出了一個JS異常,看起來不太友好。

其次是在錯誤發生后重新啟動或繼續序列的能力。 我已經讀過catchonErrorResumeNext等等,但它們都涉及另一個將在錯誤時切換到的序列。 這使生成流的邏輯變得非常復雜,我只想在其上放置一系列數字(在這個簡單的示例中)。 我有一種下沉的感覺,一旦發生錯誤,游戲就結束了,可觀察對象已完成,只能用不同的可觀察對象“重新啟動”。 我還在學習 observables; 事實上是這樣嗎?

所以我的問題是雙重的:

  1. Angular2 的異步管道可以用錯誤做一些智能的事情嗎?
  2. observables 是否有一些簡單的方法可以在錯誤后繼續?

是的,您對 catch 運算符以及在發生錯誤后執行某些操作的能力是正確的...

我會利用catch運算符來捕獲錯誤並做一些事情:

const stream = Observable.interval(1000)
  .take(5)
  .map(n => {
    if (n === 3) {
      throw Observable.throw(n);
    }
    return n;
  })
  .catch(err => {
    this.error = error;
    (...)
  });

並在模板中:

<div>{{error}}</div>

為了能夠繼續最初的 observable,您需要從發生錯誤的地方開始創建一個新的 observable:

createObservable(i) {
  return Observable.interval(1000)
    .range(i + 1, 5 - i)
    .take(5 - i)
  });
}

並在catch回調中使用它:

  .catch(err => {
    this.error = error;
    return this.createObservable(err);
  });

這兩個問題可以幫到你:

1) 不, async管道訂閱和取消訂閱並返回它接收到的事件。 您需要在它們收到async管道之前處理錯誤。

2)您可以使用 catch 運算符,當它返回一個可觀察對象時,它的值由.catch(err => Observable.of(-1))而不是錯誤發出。

您可以使用它來發出一個特殊的“錯誤”值,然后使用諸如*ngIf="num === -1類的東西以某種特殊方式顯示錯誤值。

您可以在此https://blog.thoughtram.io/angular/2017/02/27/three-things-you-didnt-know-about-the-async-pipe.html上找到更多信息

@Thierry Templier 的答案是正確的,但現在有點過時了。 以下是如何使用最新的 RXJS 進行操作。

this.myObservable$ = this.myService.myFunc().pipe(
  catchError(() => of([])) // this will emit [] if the request fails - u could handle this [] emit on error in the service itself
)

然后 HTML 正常:

<div *ngFor="let xxx of (myObservable$ | async)">
</div>

注意 Observable 名稱末尾的 $ 是 Angular 推薦的表示 Observable 的方式。

我遇到了類似的問題,並想出了另一種方法。 我不知道這是否是一個好方法,但它有效。

要在其中顯示可觀察結果的模板:

<div *ngIf="tableData$ | async as tableData; else loader" class="mt-4">
  <!-- do something with tableData -->
</div>


<ng-template #loader>
  <loading [target]="tableData$"></loading>
</ng-template>

loading組件:

export class LoadingComponent implements OnInit {

  private _errorMessageSubject : Subject<string> = new Subject<string>();
  
  private _errorMessage$ : Observable<string> = this._errorMessageSubject.asObservable();
  public get errorMessage$() : Observable<string> { return this._errorMessage$; }

  private _target : Observable<any> | null = null;
  public get target() : Observable<any> | null { return this._target }
  
  // this input does nothing except catch the error and feed the
  // message into the errorMessage subject.
  @Input() public set target(o: Observable<any> | null) { 
    if(o == null) { return; }
    this._target = o.pipe(
      catchError((error, _) => {
        this._errorMessageSubject.next(error);
        return of(null);
      }),
    );
  };
    
  
  constructor() { }

  ngOnInit(): void {
  }

}

裝載機模板:

<div *ngIf="target && target | async;">
</div>

<div *ngIf="errorMessage$ | async as error; else loading">
  <p class="text-danger">{{ error }}</p>
</div>
  
<ng-template #loading> <!-- simply a spinner icon -->
  <div class="d-flex justify-content-center">
    <fa-icon [icon]="['fas', 'spinner']" size="6x" [spin]="true"></fa-icon>
  </div>
</ng-template>

我不確定它是否是訂閱兩次可觀​​察對象的好方法,因為訂閱是在需要數據的原始組件和加載器中完成的,但除此之外,這似乎可以正常工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM