在Ajax错误之后RxJS继续侦听

时间:2014-07-21 01:45:43

标签: javascript ajax error-handling rxjs reactive-extensions-js

当内部可观察错误(Ajax请求)时,RxJs停止侦听单击事件。我试图找出如何将事件监听器挂钩到按钮单击事件并优雅地处理内部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

3 个答案:

答案 0 :(得分:22)

您可以使用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;
    });

答案 1 :(得分:6)

我遇到了自己的问题,解释了这个(和onErrorResumeNext)的运作方式。我遇到的困难是应用了什么上下文(或恢复下一个)。对我来说有意义的简单口语翻译如下:

  

给定一个可观察的流(或可观察的),catch(或onErrorResumeNext)将消耗该错误并允许您提供一个或多个可观察对象以继续原始流。

关键的一点是,您的原始资源被中断,并被您在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

答案 2 :(得分:4)

在尝试接受的答案后,我仍然有点困惑,所以这就是为我工作的结果。这就是我所拥有的:

  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
        }
      })