20

当内部可观察错误(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

4

3 回答 3

22

您可以使用catch操作符(或catchException别名)来捕获和处理 observable 中发生的错误,以便订阅者不会收到错误通知。

忽略错误:

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;
    });
于 2014-07-21T17:04:41.360 回答
6

我在解释这个(和onErrorResumeNext)如何运作时遇到了自己的问题。我遇到的难题是 catch (或resume next)适用于什么上下文。对我来说有意义的简单口语翻译如下:

给定一个可观察对象的流(或可观察对象),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'))or.onErrorResumeNext(Rx.Observable.return('N/A'))实际上不会继续您的流(由 提供interval),而是以最终的 observable(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,它显示了这一点。

于 2015-09-23T22:35:17.100 回答
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
        }
      })
于 2015-11-09T00:22:12.910 回答