web-dev-qa-db-ja.com

RxJはエラーをキャッチして続行します

解析するアイテムのリストがありますが、そのうちの1つの解析が失敗する可能性があります。

エラーをキャッチするが、シーケンスの実行を続ける「Rx-Way」とは

コードサンプル:

var observable = Rx.Observable.from([0,1,2,3,4,5])
.map(
  function(value){
      if(value == 3){
        throw new Error("Value cannot be 3");
      }
    return value;
  });

observable.subscribe(
  function(value){
  console.log("onNext " + value);
  },
  function(error){
    console.log("Error: " + error.message);
  },
  function(){
    console.log("Completed!");
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.6/rx.all.js"></script>

Rx-Way以外でやりたいこと:

var items = [0,1,2,3,4,5];

for (var item in items){
  try{
    if(item == 3){
      throw new Error("Value cannot be 3");
    }
    console.log(item);
  }catch(error){
     console.log("Error: " + error.message);
  }
}

前もって感謝します

37
Cheborra

代わりにflatMap(rxjsバージョン5ではmergeMap)を使用することをお勧めします。これにより、気にしなくてもエラーを折りたたむことができます。事実上、エラーが発生した場合に飲み込むことができる内部Observableを作成します。このアプローチの利点は、オペレーターを連結でき、パイプラインのどこかでエラーが発生すると、自動的にcatchブロックに転送されることです。

var observable = Rx.Observable.from([0, 1, 2, 3, 4, 5])
  .flatMap((value) =>          
    Rx.Observable.if(() => value != 3,
      Rx.Observable.just(value),
      Rx.Observable.throw(new Error("Value cannot be 3")))
    //This will get skipped if upstream throws an error
    .map(v => v * 2)
    .catch((err) => {
      console.log("Caught Error, continuing")
      //Return an empty Observable which gets collapsed in the output
      return Rx.Observable.empty();
    })
  );

observable.subscribe(
  (value) => console.log("onNext " + value), (error) => console.log("Error: " + error.message), () => console.log("Completed!")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.6/rx.all.js"></script>
34
paulpdaniels

新しい使い捨てストリームに切り替える必要があり、その中でエラーが発生した場合、安全に破棄され、元のストリームを維持します。

Rx.Observable.from([0,1,2,3,4,5])
    .switchMap(value => {

        // This is the disposable stream!
        // Errors can safely occur in here without killing the original stream

        return Rx.Observable.of(value)
            .map(value => {
                if (value === 3) {
                    throw new Error('Value cannot be 3');
                }
                return value;
            })
            .catch(error => {
                // You can do some fancy stuff here with errors if you like
                // Below we are just returning the error object to the outer stream
                return Rx.Observable.of(error);
            });

    })
    .map(value => {
        if (value instanceof Error) {
            // Maybe do some error handling here
            return `Error: ${value.message}`;
        }
        return value;
    })
    .subscribe(
      (x => console.log('Success', x)),
      (x => console.log('Error', x)),
      (() => console.log('Complete'))
    );
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.4.1/Rx.min.js"></script>

このブログ投稿でこの手法の詳細をご覧ください: ミートボールのクエスト:エラー発生時にRxJSストリームを継続

25
iamturns

実際にtry/catchmap関数内で使用してエラーを処理できます。これがコードスニペットです

var source = Rx.Observable.from([0, 1, 2, 3, 4, 5])
    .map(
        function(value) {
            try {
                if (value === 3) {
                    throw new Error("Value cannot be 3");
                }
                return value;

            } catch (error) {
                console.log('I caught an error');
                return undefined;
            }
        })
    .filter(function(x) {
        return x !== undefined; });


source.subscribe(
    function(value) {
        console.log("onNext " + value);
    },
    function(error) {
        console.log("Error: " + error.message);
    },
    function() {
        console.log("Completed!");
    });
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.6/rx.all.js"></script>
0
Toan Nguyen