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」がない場合は、エラーをスローします。そのため、私のサブスクリプションでは、以下で説明する2番目のパラメーター(handleError)に入ります。

.subscribe(success, handleError)

助言がありますか?


4
どうthrow 'Valid token not returned';ですか?
ギュンターZöchbauer

コンパイルに失敗する
Hassan

正確なエラーメッセージをお願いします。
ギュンターZöchbauer

2
申し訳ありませんreturn throw 'message here'が、returnキーワードでは機能しませんが、キーワードなしでは機能します。論理的に正しく機能しているかどうかを確認します。
ハッサン

エラーテキストはsubscribeメソッドで受信されておらず.finally()、ストリーム内でもトリガーされます。(ただし、実行は停止されます。これは良いことです)
Hassan

回答:


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()、あなたが返すものを気にしません。そこからObservableを返しても、通知map()として渡されますnext

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

2019年1月:RxJS6用に更新


1
ありがとう@ martin-はい、あなたのソリューションは機能します。@GünterZöchbauerが指摘したlogErrorメソッド内にも実際に問題がありました。私はreturnそれからエラーオブジェクトを取得する必要がありましたが、今では完全に機能します:)ありがとう!
ハッサン

@martin:ここで.catch()を使用したくない理由を説明していただけますか?
ボブ

1
@Bob OPはcatch()エラーのログ記録と再スローのみに使用していたため、副作用(エラーのログ記録)を実行したいだけで、より簡単に使用できる場合は不要ですdo()
martin

1
これはと同じreturn throwError(new Error('Valid token not returned'));ですか?
Simon_Weaver 2018

@Simon_Weaverいいえ、そうではありません。return throwError()を返しますObservable<never>。これは、まったく戻らずに、監視可能なストリームをただちに中断します。
モニカを復活させる

25

あなたは次のように感じる場合throw new Error()は、使用できるように、未観測可能-ようだ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 
   }
});

またはより簡潔に:

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

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

あなたは文字通り、パイプ内のhttp監視可能から別の監視可能に「切り替える」と言っています。これは単に出力値を「ラップ」するか、新しい「エラー」監視可能です。

置くことを忘れないでください、さもないとofあなたはいくつかの紛らわしいエラーメッセージを受け取るでしょう。

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


4
switchMap非同期ifステートメントとして考え始めたら-物事はもっと理にかなっています:
Simon_Weaver19年

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を使用する方が良いでしょうか?誰かが別の演算子を提案したり、直接編集したりできますか?
christo89 8919年

私は提案をすることを考えてthrow new Error()今のところ最良の選択肢である
SF
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.