web-dev-qa-db-ja.com

RxJSはAjaxエラー後もリッスンを続けます

RxJは、内部で観察可能なエラー(Ajaxリクエスト)が発生すると、クリックイベントのリッスンを停止します。イベントリスナーをボタンクリックイベントにフックしたままにして、内部のajaxエラーを適切に処理する方法を見つけようとしています。

これが私のサンプルコードとplunkrへのリンクです

var input = $("#testBtn");
var test = Rx.Observable.fromEvent(input,'click');

var testAjax = function() {
  return Rx.Observable.range(0,3).then(function(x){ 
    if(x==2)throw "RAWR"; //Simulating a promise error.
    return x;
  });
}

test.map(function(){
  return Rx.Observable.when(testAjax());
})
.switchLatest()
.subscribe(
  function (x) {
      console.log('Next: ', x);
  },
  function (err) {
      console.log('Error: ' + err);   
  },
  function () {
      console.log('Completed');   
  });

http://plnkr.co/edit/NGMB7RkBbpN1ji4mfzih

20
Jonathan Sheely

catch演算子(またはcatchExceptionエイリアス)を使用して、オブザーバブルで発生するエラーをキャッチして処理し、サブスクライバーにエラーが通知されないようにすることができます。

エラーを無視する:

return Rx.Observable
    .when(testAjax())
    .catch(Rx.Observable.empty()); // continues with an empty obs after error.

エラーの処理:

var empty = Rx.Observable.return('default value');
return Rx.Observable
    .when(testAjax())
    .catch(function (error) {
        console.log('error:', error);
        return empty;
    });
22
cwharris

これ(およびonErrorResumeNext)がどのように機能するかを解釈する私自身の問題に遭遇しました。私が遭遇した苦労は、キャッチ(またはresume next)がどのコンテキストに適用されたかでした。私にとって意味のある簡単な口語訳は次のとおりです。

オブザーバブルのストリーム(またはオブザーバブル)が与えられると、catch(またはonErrorResumeNext)はエラーを消費し、元のストリームを継続するために1つ以上のオブザーバブルを提供できるようにします。

重要なポイントは、元のソースが中断され、catch/onErrorResumeNext関数で指定したオブザーバブルに置き換えられることです。これは、次のようなものがある場合を意味します。

var src = Rx.Observable
    .interval(500)
    .take(10)
    .select(function(x) {
        if (x == 5) {
            return Rx.Observable.throw('Simulated Failure');
        }

        return Rx.Observable.return(x * 2);
    })

次に、.catch(Rx.Observable.return('N/A'))または.onErrorResumeNext(Rx.Observable.return('N/A'))を追加すると、実際にはストリームが継続されるだけでなく(intervalによって供給されます)、最終的な監視対象(N/A)でストリームが終了します。

代わりに、障害を適切に処理して元のストリームを続行する場合は、.select(function(x) { return x.catch(Rx.Observable.return('N/A')); })のようなものにする必要があります。これで、ストリームは、キャッチされたデフォルトで失敗したストリーム内の監視可能な要素を置き換えてから、既存のソースストリームを続行します。

var src = Rx.Observable
    .interval(500)
    .take(10)
    .select(function(x) {
        if (x == 5) {
            return Rx.Observable.throw('Simulated Failure');
        }

        return Rx.Observable.return(x * 2);
    })
    //.catch(Rx.Observable.return('N/A'))
    //.onErrorResumeNext(Rx.Observable.return('N/A'))
    .select(function(x) { return x.catch(Rx.Observable.return('N/A')); })
    .selectMany(function(x) { return x; });


var sub = src.subscribe(
    function (x) { console.log(x); },
    function (x) { console.log(x); },
    function () { console.log('DONE'); }
);

// OUTPUT:
// 0
// 2
// 4
// 6
// 8
// N/A
// 12
// 14
// 16
// 18
// DONE

これが JSFiddle で、これが実際に動作していることを示しています。

6
pjs

受け入れられた答えを試した後、私はまだ少し混乱していたので、これが私のために働いた結果でした。これは私が持っていたものです:

  Rx.Observable.fromEvent(emitter, events.SUBMIT_EVENT)
      .flatMapFirst(email=>{
        return $.ajax({
          method: "POST",
          url: '/email',
          data: {
            email: email
          },
        }).promise()
      })
      .subscribe(response=>{
        if (response) {
          //do your success thing here
            }
          },
         error =>{
           //do your error thing
          }
         )

サーバーがエラーを返したとき(ユーザーがすでに電子メールを入力したときなど)、ユーザーの電子メールフォームの送信を再度聞くことができませんでした。これは私のために働いたものです:

  Rx.Observable.fromEvent(emitter, events.SUBMIT_EVENT)
      .flatMapFirst(email=>{
        return $.ajax({
          method: "POST",
          url: '/email',
          data: {
            email: email
          },
        }).promise()
      })
      .doOnError(error=> {
        //do your error thing here
      })
      .retry()
      .subscribe(response=>{
        if (response) {
          //do your success thing here
        }
      })
4
taylorstine