【问题标题】:RxJS Continue Listening After Ajax ErrorRxJS 在 Ajax 错误后继续监听
【发布时间】:2014-09-11 11:03:04
【问题描述】:

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

【问题讨论】:

  • 您使用whenthen 的目的是什么?它看起来不像在给你买任何东西......
  • 这只是作为伪造 ajax 请求的示例。此处提供了一个 mockjax 示例。 plnkr.co/edit/UtReTejs524rX2DKbIoj?p=preview

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


【解决方案1】:

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

【讨论】:

  • 谢谢!我在那里就像 90%。我发现运行 catch() 是我需要在内部 observable 上运行的,但无法弄清楚返回值应该是什么。最终Rx.Observable.Empty() 是我所缺少的。这是一个更新的 plunker plnkr.co/edit/UtReTejs524rX2DKbIoj?p=preview
  • +1 用于最终自己找到答案。 :) 另外,如果有疑问,只需创建一个 observable:Observable.create。只要确保保持卫生即可。
  • 如果我将 catch() 放在外部 Observable 上,在 flatMapLatest 之后它将完成订阅。仅当我处理内部可观察对象上的所有异常时,这似乎才有效。有什么建议吗?
  • 正确。 flatMapLatest 没有处理它订阅的 observable 错误的机制,所以你有几个选择。 1)不要让这些错误“冒泡”到flatMapLatest,或者 2)创建一个可以容纳值或错误的“类型”,并让 flatMapLatest 通过 onNext “冒泡”这两者。在订阅者方面,您可以为该类型“模式匹配”,并决定如何处理错误/值。
  • 如果我希望订阅者收到错误通知并且流能够正常继续,该怎么办?
【解决方案2】:

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

给定一个 observable 流(或 observable),catch(或 onErrorResumeNext)将处理错误并允许您提供一个或多个 observable 以继续原始流。

关键是您的原始来源被中断并替换为您在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,它显示了这一点。

【讨论】:

  • selectMany(function(x) { return x; }) 是做什么的?
  • 这个策略产生一个可观察的事件流。 selectMany(或flatMap)通过展开内部可观察对象来扩展流,使其成为可观察的结果流(在本例中为字符串)。
【解决方案3】:

在尝试接受的答案后我仍然有点困惑,所以这就是最终对我有用的方法。这就是我所拥有的:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-07
    • 2012-04-01
    相关资源
    最近更新 更多