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

问题描述 投票:1回答:2

所以我通常会写这样的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', []))
    );
}

这是多么隐含的好处,因为它对我来说似乎很冗长,我个人从来没有必要管道我的错误。

angular rxjs angular2-observables
2个回答
1
投票

这一切都与关注的分离有关。

使用catchError的一个主要好处是分离整个数据检索逻辑,包括从数据表示过程中可能出现的所有错误。

Let Components only care about the presentation of data

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

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

假设您的数据是项目列表。你的组件会调用service.getItemList()函数,因为它只关心数据,所以会期望:

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

您可以使用组件模板中的ngIf轻松处理所有这些情况,并根据具体情况显示数据或其他内容。使用Service函数返回一个'clean'Observable,它只返回数据(或null)并且不会抛出任何错误,因此您可以轻松地在模板中使用AsyncPipe来订阅代码。

Don't let Components care about data retrieval specifics like errors

您的数据检索和错误处理逻辑可能会随时间而变化。也许你正在升级到一个新的Api,突然不得不处理不同的错误。不要让您的组件担心这一点。将此逻辑移至服务。

从组件中删除数据访问意味着您可以随时改变您对实现的想法,而无需触及任何组件。他们不知道服务如何运作。 [Angular tutorial]

Put the data retrieval and error handling logic in a Service

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

在数据检索服务中,您可以使用catchError运算符详细处理错误。也许你想对所有错误做些什么,比如:

  • 记录下来
  • 显示面向用户的错误消息作为通知(请参阅Show messages
  • 获取替代数据或返回默认值

将其中的一部分移动到this.handleError('getHeroes', [])函数可以防止重复代码。

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

您可能还需要从新组件调用现有服务功能。在服务函数中使用错误处理逻辑可以很容易,因为从新组件调用函数时不必担心错误处理。

因此,它归结为将数据检索逻辑(在服务中)与数据表示逻辑(在组件​​中)分开,以及将来扩展应用程序的难易程度。


1
投票

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

因为每个服务方法都返回一个不同类型的Observable结果,所以catchError中的函数就像handleError()这样接受一个类型参数,因此它可以返回安全值作为应用程序所期望的类型。


0
投票

刚刚遇到这个并认为我会更新我的发现以更好地回答我自己的问题。

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

主要原因是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'}) //将返回由此声明的observable,从而发出需要在订阅时触发错误

示例二 - catchError(err, catchedObservable} //这将实际上尝试在发生错误时再次调用失败的observable,从而再次阻止调用错误方法。

© www.soinside.com 2019 - 2024. All rights reserved.