简体   繁体   English

如何从 RxJS 地图运算符(角度)抛出错误

[英]How to throw error from RxJS map operator (angular)

I want to throw an error from my observable's map operator based on a condition.我想根据条件从我的 observable 的map运算符中抛出错误。 For instance if correct API data is not received.例如,如果没有收到正确的 API 数据。 Please see the following code:请看以下代码:

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.") );
}

Basically as you can see in the code, if the response (res object) doesn't have 'bearerToken' i want to throw out an error.基本上正如您在代码中看到的那样,如果响应(res 对象)没有“bearerToken”,我想抛出一个错误。 So that in my subscription it goes into the 2nd parameter (handleError) mentioned below.因此,在我的订阅中,它会进入下面提到的第二个参数 (handleError)。

.subscribe(success, handleError)

Any suggestions?有什么建议么?

Just throw the error inside the map() operator.只需在map()运算符中抛出错误即可。 All callbacks in RxJS are wrapped with try-catch blocks so it'll be caught and then sent as an error notification. RxJS 中的所有回调都用 try-catch 块包装,因此它会被捕获,然后作为error通知发送。

This means you don't return anything and just throw the error:这意味着您不返回任何内容而只是抛出错误:

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

The throwError() (former Observable.throw() in RxJS 5) is an Observable that just sends an error notification but map() doesn't care what you return. throwError() (RxJS 5 中的前Observable.throw() )是一个 Observable,它只发送一个error通知,但map()并不关心你返回什么。 Even if you return an Observable from map() it'll be passed as next notification.即使你从map()返回一个 Observable 它也会作为next通知传递。

Last thing, you probably don't need to use .catchError() (former catch() in RxJS 5).最后一件事,您可能不需要使用.catchError() (RxJS 5 中的前catch() )。 If you need to perform any side effects when an error happens it's better to use tap(null, err => console.log(err)) (former do() in RxJS 5) for example.例如,如果您需要在发生错误时执行任何副作用,最好使用tap(null, err => console.log(err)) (前 RxJS 5 中的do() )。

Jan 2019: Updated for RxJS 6 2019 年 1 月:针对 RxJS 6 更新

If you feel like throw new Error() seems un-observable-like you can use return throwError(...) with switchMap instead of map (the difference being switchMap has to return a new observable instead of a raw value):如果你觉得throw new Error()看起来像是不可观察的,你可以使用return throwError(...)switchMap而不是map (不同的是switchMap必须返回一个新的可观察值而不是原始值):

// this is the import needed for throwError()
import { throwError } from 'rxjs';


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

or more concisely:或更简洁地说:

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

The behavior will be the same, it's just a different syntax.行为将是相同的,只是语法不同。

You're literally saying 'switch' from the HTTP observable in the pipe to a different observable, which is either just 'wrapping' the output value, or a new 'error' observable.您实际上是在说从管道中的 HTTP observable 到不同的 observable 的“切换”,这要么只是“包装”输出值,要么是一个新的“错误”observable。

Don't forget to put of or you'll get some confusing error messages.不要忘记 put of否则你会得到一些令人困惑的错误消息。

Also the beauty of 'switchMap' is that you can return a whole new 'chain' of commands if you wanted to - for whatever logic needs to be done with saveJwt .此外,“switchMap”的美妙之处在于,如果您愿意,您可以返回一个全新的“命令链”——无论需要使用saveJwt完成的任何逻辑。

Even though this question is already answered, I'd like to share my own approach (even though its only slightly different from above).即使这个问题已经得到回答,我还是想分享我自己的方法(尽管它与上面的略有不同)。

I would decide what is returned separate from the mapping and vice versa.我会决定从映射中分离返回什么,反之亦然。 I'm not sure what operator is best for this so I'll use tap .我不确定哪种运算符最适合此操作,因此我将使用tap

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM