web-dev-qa-db-ja.com

振る舞いの件名にエラーをスローしてストリームを続行するにはどうすればよいですか?

一方では、時々エラーをスローするストリームがあります:

_this.behaviorSubject.error(error)
_

ただし、後で、ストリームを続行します。

_this.behaviorSubject.next(anotherValue)
_

一方、behaviorSubject.asObservable()にサブスクライブしているサブスクライバーがあります。

サブスクリプションでは、値とエラーを処理しています。

_.subscribe( 
   ( value ) =>  {  /* ok */ },
   ( error ) =>  {  /* some error */ }
);
_

エラーが発生するたびにonSuccessが呼び出され、将来のonErrorの呼び出しを妨げない、単純なonErrorおよびonSuccessコールバックと同じ効果が必要です。作られています。 RXJSでこれを行うにはどうすればよいですか?

私はキャッチを調べましたが、サブスクライバーでエラーが呼び出されるのを防ぐだけのようです。

24
David

短い答え:それは不可能です。

これの使用方法: RxJSの基本概念は、errorまたはcomplete- callが基本的に"kill"になることです。ストリーム。この概念により、強制的に"必要に応じてエラーをあちこちに投げるだけ"ではなく、アプリケーション内のエラーとデータの流れを適切に処理します。たとえば、BehaviorSubjectは通常、データを保持するためのものですが、 not を使用して、そのデータを取得/作成し、発生する可能性のあるエラーを処理するプロセスも含める必要がありますデータの取得中。

本を読むにしたい場合は、フローを2つの部分に分割する必要があります

  1. データの取得/作成:一度実行されると、エラーが発生するたびに完了またはエラーをスローするストリーム。データが取得されると、ストアに送信されます。
  2. Thestore (たとえば、あなたの場合:BehaviorSubjectsの束):有効なデータのみがストアに到着します。つまり、ここではエラー処理は行われず、ストアは、正しいデータを保持していることをストアで信頼できます。

例として、データフローは次のようになります(概略図として)。

store.ts

dataStore: BehaviorSubject<IData> = new BehaviorSubject<IData>();
errorMessage: BehaviorSubject<IErrorMsg> = new BehaviorSubject<IErrorMsg>();

data-retrieval.ts

fetchDataById(id: string) {
    httpService.get(`some/rest/endpoint/${id}`)
        .subscribe(handleData, handleError);
}

handleData(data: IData) {
    errorMessage.next(null);
    dataStore.next(data);
}

handleError(error: Error) {
    errorMessage.next(error.message);
    dataStore.next(null);
}

"しかし、これは多くのオーバーヘッドのように見えます..."-True、ただし、アプリケーション内のデータのクリーンで理解しやすいフローを保証し、テストと保守が容易です。 ngrxredux のようなすぐに使用できるストアコンセプトもあります。

21
olsn

Rxは基本的に、オブザーバブルがアクティブまたはファイナライズされる(onCompleteまたはonError)という概念に基づいて構築されています。 Observableがファイナライズしているとき、上流のObservableからサブスクライブを解除します。 _.catch_はその動作を修正できません。エラーを他の何かにマッピングするオプションのみを提供します。

_Rx.Observable.interval(500)
  .mergeMap(i => i % 3 == 2 ? Rx.Observable.throw(new Error('kboom')) : Rx.Observable.of(i))
  .catch(err => Rx.Observable.of(err.message))
  .subscribe(
    val => console.log('val: ' + val),
    err => console.log('err: ' + err),
    () => console.log('stream completed')
  )
_

この例は、5回ではなく3回の排出後に完了することに注意してください。

this.behaviorSubject.error(error)を呼び出すと、サブジェクトに含まれるObservableを内部的に確定します。何らかの方法でエラーを発生させたい場合は、エラーを非エラー値にする必要があります。

_this.behaviorSubject.next({ value: 'somevalue' });
this.behaviorSubject.next({ error: error });
this.behaviorSubject.next({ value: 'somevalue' });
_

その後、放出された値のプロパティに基づいて、実行するアクションを区別できます。

4

これはあなたの状況ではうまくいかないかもしれませんが、Angular 2で作業するときにこの同じ問題に遭遇しました。なぜなら、画面間をナビゲートし、サービスがAPI関数がコンストラクターで呼び出され、エラー関数がまだ準備ができていないUIを更新しようとするため、実際には大きな問題が発生します。

私がやったことはうまく動作し、かなりきれいであるようです。エラーハンドラーで件名のリセットを作成しました。

subject.subscribe( 
   ( value ) =>  {  /* ok */ },
   ( error ) =>  {  
      //handle error
      //reset subject
      this.subject = new Subject<any>();
   }
);

これは、画面に移動するたびに新しいサブスクリプションが古い画面から破棄され、新しい画面で設定されるため、新しいサブジェクトが何も傷つけないため、これが機能します。

0
KickerKeeper