如何从RxJS映射运算符引发错误(角度)


93

我想根据条件从我的可观察的地图运算符中引发错误。例如,如果未收到正确的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.") );
}

基本上就像您在代码中看到的那样,如果响应(res对象)不具有“ bearerToken”,我想抛出一个错误。因此,在我的订阅中,它进入了下面提到的第二个参数(handleError)。

.subscribe(success, handleError)

有什么建议么?


4
throw 'Valid token not returned';
君特Zöchbauer

无法编译
Hassan

请提供确切的错误信息。
君特Zöchbauer

2
抱歉,它不能使用,return throw 'message here'但没有return关键字也可以使用。让我检查其逻辑上是否正确运行。
哈桑

subscribe方法中未接收到错误文本.finally(),并且流中的也会触发。(但是,停止执行是一件好事)
Hassan

Answers:


141

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

这意味着您什么也不返回,只抛出错误:

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

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

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

2019年1月:已针对RxJS 6更新


1
感谢@martin-是的,您的解决方案有效。@GünterZöchbauer指出,我的logError方法内部实际上也有问题。我不得不return从它的错误对象,现在它可以完美地工作:)谢谢!
哈桑

@martin:能否请您解释一下为什么我们不想在这里.catch()?
鲍勃

1
@Bob因为OPcatch()仅用于记录并重新抛出错误,所以如果您只想执行副作用(记录错误),则不需要这样做,并且使用起来更容易do()
马丁

1
这等同于return throwError(new Error('Valid token not returned'));吗?
Simon_Weaver

@Simon_Weaver不,不是。return throwError()返回Observable<never>,这只会立即中断可观察的流,而根本不会返回。
恢复莫妮卡

25

如果您觉得throw new Error()好像不可观察,可以使用throwError(...)withswitchMap代替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 
   }
});

或更简而言之:

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

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

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

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

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


3
一旦我开始考虑将其switchMap视为异步if语句,事情就变得更加有意义了:-)
Simon_Weaver

3

即使已经回答了这个问题,我也想分享我自己的方法(即使与上面的方法略有不同)。

我会决定与映射分开返回什么,反之亦然。我不确定哪种运算符最适合此操作,所以我将使用tap

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

的返回值将tap被忽略。此代码执行的操作与说的不同
SF

我仍然习惯于rxjs。使用switchMap会更好吗?有人可以建议其他运算符还是直接编辑?
christo8989

我认为,建议的方法throw new Error()是迄今为止最好的选择
SF
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.