繁体   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