web-dev-qa-db-ja.com

キャッチでエラーを無視して続行するRxJS

こんにちは私は次のコードを持っています。エラーがスローされたときにメイン(アップストリーム)Observableが削除されないようにする方法を知りたいです。

すべての数値が「4」を期待するように次のコードを変更するにはどうすればよいですか?

さまざまな演算子で他のケースで機能する一般的なパターンソリューションを探しています。これは私が思いつくことができる最も単純なケースです。

const Rx = require('rxjs/Rx');

function checkValue(n) {
  if(n === 4) {
    throw new Error("Bad value");
  }
  return true;
}
const source = Rx.Observable.interval(100).take(10);

source.filter(x => checkValue(x))
  .catch(err => Rx.Observable.empty())
  .subscribe(v => console.log(v));
12
devguy

ソースオブザーバブルを実行したままにする必要がありますが、メインイベントストリームでエラーを発生させると、オブザーバブル全体が折りたたまれ、アイテムを受信できなくなります。

解決策は、上流のパイプを崩さずにフィルター処理およびキャッチできる分離されたストリームを作成することです。

_const Rx = require('rxjs/Rx');
function checkValue(n) {
  if(n === 4) {
    throw new Error("Bad value");
  }
  return true;
}
const source = Rx.Observable.interval(100).take(10);

source
  // pass the item into the projection function of the switchMap operator
  .switchMap(x => {
     // we create a new stream of just one item
     // this stream is created for every item emitted by the source observable
     return Observable.of(x)
       // now we run the filter
       .filter(checkValue)
       // we catch the error here within the projection function
       // on error this upstream pipe will collapse, but that is ok because it starts within this function and will not effect the source
       // the downstream operators will never see the error so they will also not be effect
       .catch(err => Rx.Observable.empty());
     })
     .subscribe(v => console.log(v));
_

また、catchセレクターに渡された2番目の引数を使用して、監視可能なソースを再起動することもできますが、これにより、以前に実行されていないかのように起動されます。

_const Rx = require('rxjs/Rx');

function checkValue(n) {
  if(n === 4) {
    throw new Error("Bad value");
  }
  return true;
}
const source = Rx.Observable.interval(100).take(10);

source.filter(x => checkValue(x))
  .catch((err, source) => source)
  .subscribe(v => console.log(v));
_

しかし、これでは望ましい効果が得られません。時間の終わりまで1..3を繰り返し放出するストリームが表示されます...またはスクリプトをシャットダウンします。いずれか早い方。 (これは.retry()の機能に不可欠です)

12

フィルタリングを行う場所では、flatMapオペレーターを使用する必要があります。この例のflatMapでは、Observable.if()を使用してフィルタリングを行っています。これにより、常に監視可能オブジェクトが返されることが保証されます。他の方法でもできると思いますが、これは私にとってクリーンな実装です。

const source = Rx.Observable.interval(100).take(10).flatMap((x)=>
    Rx.Observable.if(() => x !== 4, 
    Rx.Observable.of(x),
    Rx.Observable.throw("Bad value"))
    .catch((err) => {
        return Rx.Observable.empty()
    })
);

source.subscribe(v => console.log(v));
0
zinyando