为什么用catchError处理错误而不是在Angular的订阅错误回调中处理

时间:2019-02-19 16:47:43

标签: angular rxjs angular2-observables

所以我通常会这样写我的http请求

服务

getData(){
  return this.http.get('url')
}

组件

getTheData() {
  this.service.getData().subscribe(
    (res) => {
      //Do something
    }, 
    (err) => {
      console.log('getData has thrown and error of', err)
    })

但是在浏览Angular文档时,他们似乎在服务中格式化了

getHeroes(): Observable<Hero[]> {
  return this.http.get<Hero[]>(this.heroesUrl)
    .pipe(
      catchError(this.handleError('getHeroes', []))
    );
}

这个隐含的上行空间是什么,因为它对我来说似乎很冗长,而且我个人从来就不需要传达我的错误。

3 个答案:

答案 0 :(得分:1)

根据Angular团队
““ handleError()方法报告错误,然后返回无害的结果,以便应用程序继续运行”。

由于每种服务方法都返回不同类型的Observable结果,因此catchError中的函数(例如handleError())采用类型参数,因此可以返回安全值作为应用程序期望的类型。

答案 1 :(得分:1)

这完全是关注点分离。

使用catchError的一个主要好处是 将整个数据检索逻辑(包括所有在显示过程中可能发生的错误)与数据的呈现分开。

让Components只在乎数据的显示方式

组件仅应关心数据(无论是否存在)。他们不应该关心如何检索数据的细节,也不必关心数据检索过程中可能出错的所有事情。

  

组件不应该直接获取或保存数据,它们当然   不应故意提供虚假数据。他们应该专注于呈现   数据并委托对服务的数据访问。 [Angular tutorial]

假设您的数据是一个项目列表。您的组件将调用service.getItemList()函数,并且由于它只关心数据,因此可以期望:

  • 包含项目的列表
  • 一个空列表
  • 没有列表,即nullundefined

您可以使用Component模板中的ngIf轻松处理所有这些情况,并根据情况显示数据或其他内容。让Service函数返回一个“干净”的Observable,该Observable仅返回数据(或null),并且不会引发任何错误,这使您组件中的代码保持精简,因为您可以轻松地使用AsyncPipe订阅模板。

不要让组件关心诸如错误之类的数据检索细节

您的数据检索和错误处理逻辑可能会随时间变化。也许您要升级到新的Api,突然不得不处理其他错误。不要让您的组件为此担心。将此逻辑移至服务。

  

从组件中删除数据访问权限意味着您可以改变主意   随时实施,而无需涉及任何组件。他们不   了解服务的运作方式。 [Angular tutorial]

将数据检索和错误处理逻辑放在服务中

处理错误是数据检索逻辑的一部分,而不是数据表示逻辑的一部分。

在数据检索服务中,您可以使用catchError运算符来详细处理错误。也许您想对所有错误执行某些操作,例如:

  • 记录
  • 将面向用户的错误消息显示为通知(请参见Show messages
  • 获取备用数据或返回默认值

将其中的一些内容移至this.handleError('getHeroes', [])函数中可以避免代码重复。

  

将错误报告给控制台后,处理程序将构造一个用户   友好的消息,并向应用程序返回安全值,以便它可以保持   工作。 [Angular tutorial]

有时您还需要从新组件调用现有Service函数。在Service函数中使用错误处理逻辑可以简化此操作,因为从新Component调用函数时,您不必担心错误处理。

因此归结为将数据检索逻辑(在Services中)与数据表示逻辑(在Components中)和将来扩展应用程序的简便性分开。

答案 2 :(得分:0)

只是碰到了这一点,以为我会更新自己的发现以更好地回答我自己的问题。

虽然从组件中抽象出错误处理逻辑的要点是一个完全有效的点,而最主要的要点是一个原因,但还有其他一些原因使得catchError不仅可以使用订阅错误方法来处理错误,还可以使用。 / p>

主要原因是catchError允许您处理http.get或在管道方法内发生错误的第一个运算符返回的observable,即

this.http.get('url').pipe(filter(condition => condition = true), map(filteredCondtion => filteredCondition = true), catchError(err, return throwError(err)).subscribe(......)

因此,如果这些运算符中的任何一个由于某种原因而失败,则catchError会捕获从该错误返回的可观察到的错误,但是使用catchError遇到的主要好处是可以防止可观察到的流在事件中关闭错误。

使用throwErrorcatchError(err throw 'error occcured')将导致订阅方法的错误部分被调用,从而关闭可观察的流,但是像这样使用catchError

示例一-catchError(err, of({key:'streamWontError'}) //将返回of声明的可观察对象,从而发出需要在订阅上触发错误的情况

示例二-catchError(err, catchedObservable} //实际上,如果发生错误,这实际上将尝试再次调用失败的可观察对象,从而再次阻止错误方法的调用。