web-dev-qa-db-ja.com

RxJSマップオペレーターからエラーをスローする方法(角度)

条件に基づいて、オブザーバブルの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.") );
}

基本的にコードでわかるように、応答(resオブジェクト)に 'bearerToken'がない場合、エラーをスローする必要があります。そのため、私のサブスクリプションでは、後述の2番目のパラメーター(handleError)に入ります。

.subscribe(success, handleError)

助言がありますか?

54
Hassan

map()演算子内でエラーをスローするだけです。 RxJSのすべてのコールバックはtry-catchブロックでラップされているため、キャッチされてerror通知として送信されます。

つまり、何も返さずにエラーをスローするだけです。

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

throwError()(RxJS 5の以前のObservable.throw())は、error通知を送信するだけのObservableですが、map()は何を返すかを気にしません。 map()からObservableを返した場合でも、next通知として渡されます。

最後に、おそらく.catchError()(RxJS 5の以前のcatch())を使用する必要はないでしょう。エラーが発生したときに副作用を実行する必要がある場合は、たとえばtap(null, err => console.log(err))(RxJS 5では以前のdo())を使用することをお勧めします。

2019年1月:RxJS 6用に更新

94
martin

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');
   }
});

またはより簡潔に:

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

動作は同じになり、構文が異なります。

文字通り、パイプ内のhttpオブザーバブルから別のオブザーバブルへの「切り替え」を言います。これは、出力値を単に「ラップ」するか、新しい「エラー」オブザーバブルです。

ofを忘れずに入力すると、わかりにくいエラーメッセージが表示されます。

また、「switchMap」の利点は、saveJwtを使用して実行する必要があるロジックに対して、まったく新しいコマンドチェーンを返すことができることです。

6
Simon_Weaver

この質問はすでに回答されていますが、私は自分のアプローチを共有したいと思います(上記とわずかに異なる場合でも)。

マッピングとは別に返されるものを決定し、逆も同様です。どの演算子がこれに最適かわからないので、tapを使用します。

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