如何从RxJS映射运算符抛出错误(angular)

Has*_*san 65 rxjs typescript angular

我想根据条件从我的observable的map运算符中抛出一个错误.例如,如果未收到正确的API数据.请参阅以下代码:

private userAuthenticate( email: string, password: string ) {
    return this.httpPost(`${this.baseApiUrl}/auth?format=json&provider=login`, {userName: email, password: password})
        .map( res => { 
            if ( res.bearerToken ) {
                return this.saveJwt(res.bearerToken); 
            } else {
                // THIS DOESN'T THROW ERROR --------------------
                return Observable.throw('Valid token not returned');
            }
        })
        .catch( err => Observable.throw(this.logError(err) )
        .finally( () => console.log("Authentication done.") );
}
Run Code Online (Sandbox Code Playgroud)

基本上你可以在代码中看到,如果响应(res对象)没有'bearerToken',我想抛出一个错误.所以在我的订阅中它会进入下面提到的第二个参数(handleError).

.subscribe(success, handleError)
Run Code Online (Sandbox Code Playgroud)

有什么建议?

mar*_*tin 105

只需将错误抛出map()操作员.RxJS中的所有回调都包含在try-catch块中,因此它将被捕获,然后作为error通知发送.

这意味着你不返回任何东西,只是抛出错误:

map(res => { 
  if (res.bearerToken) {
    return this.saveJwt(res.bearerToken); 
  } else {
    throw new Error('Valid token not returned');
  }
})
Run Code Online (Sandbox Code Playgroud)

throwError()(前Observable.throw()中RxJS 5)可观察到的,只是发送error通知,但map()不关心你返回的内容.即使你从map()它返回一个Observable,它也会作为next通知传递.

最后,您可能不需要使用.catchError()(以前catch()在RxJS 5中).如果您在发生错误时需要执行任何副作用,最好使用tap(null, err => console.log(err))(do()例如在RxJS 5中).

2019年1月:更新了RxJS 6


Sim*_*ver 10

如果您觉得throw new Error()似乎不可观察,可以使用switchMap

// RxJS 6+ syntax
this.httpPost.pipe(switchMap(res => { 
   if (res.bearerToken) {
      return of(this.saveJwt(res.bearerToken)); 
   } 
   else {
      return throwError('Valid token not returned');
   }
});
Run Code Online (Sandbox Code Playgroud)

或更简而言之:

this.httpPost.pipe(switchMap(res => (res.bearerToken) ? 
                                    of(this.saveJwt(res.bearerToken)) : 
                                    throwError('Valid token not returned')
));
Run Code Online (Sandbox Code Playgroud)

行为将是相同的,只是语法不同。

您实际上是说从管道中的http可观察变量“切换”到另一个可观察变量,即只是“包装”输出值,或者是新的“错误”可观察变量。

不要忘了放,of否则您会收到一些令人困惑的错误消息。

'switchMap'的优点还在于,如果需要,您可以返回一条全新的“链”命令-无论需要使用什么逻辑saveJwt

  • 一旦我开始将“switchMap”视为异步“if”语句 - 事情就变得更有意义了:-) (7认同)
  • 请注意,从 RxJS 8 开始,参数为原语(例如错误消息)的 `throwError(...)` 将被弃用。相反,传递一个错误工厂函数,即“ throwError(() => new Error(...))”。 (2认同)

chr*_*989 6

即使这个问题已经得到回答,我还是想分享我自己的方法(尽管它与上面的略有不同)。

我会决定从映射中分离返回什么,反之亦然。我不确定哪种运算符最适合此操作,因此我将使用tap.

this.httpPost.pipe(
  tap(res => { 
    if (!res.bearerToken) {
      throw new Error('Valid token not returned');
    }
  }),
  map(res => this.saveJwt(res.bearerToken)),
);
Run Code Online (Sandbox Code Playgroud)

  • 我首先对这种方法持怀疑态度,但 rxjs 文档有类似的示例 https://rxjs.dev/api/operators/tap#example-2 (2认同)