使用rx-angular重新订阅一个observable

时间:2014-09-03 10:02:47

标签: angularjs rxjs

我想使用angular-rx作为结果的简单刷新按钮。如果用户单击刷新按钮,则重新加载结果。如果用户在1秒内单击刷新按钮100次,则仅加载最新结果。如果结果由于某种原因失败,那并不意味着刷新按钮应该停止工作。

为了达到最后一点,我想保留订阅(或重新订阅),即使它失败了,但我无法弄清楚如何做到这一点?

这不起作用,但这是一个简单的例子,我尝试重新订阅错误:

var refreshObs = $scope.$createObservableFunction('refresh');

var doSubscribe = function () {
  refreshObs
  .select(function (x, idx, obs) {
      // get the results.
      // in here might throw an exception
  })
  .switch()
  .subscribe(
  function (x) { /*show the results*/ }, // on next
  function (err) { // on error
      doSubscribe(); // re-subscribe
  },
  function () { } // on complete
  );
};
doSubscribe();

我认为这很常见,应该有一些标准的做法来实现这个目标吗?

更新

使用建议的解决方案,这就是我所做的测试:

// using angularjs and the rx.lite.js library
var testCount = 0;
var obsSubject = new rx.Subject(); // note. rx is injected but is really Rx
$scope.refreshButton = function () { // click runs this
  obsSubject.onNext();
};

obsSubject.map(function () {
  testCount++;
  if (testCount % 2 === 0) {
      throw new Error("something to catch");
  }
  return 1;
})
.catch(function (e) {
  return rx.Observable.return(1);
})
.subscribe(
    function (x) {
    // do something with results
});

这些是我的测试结果:

  1. 点击了刷新按钮
  2. obsSubject.onNext()调用
  3. map函数返回1。
  4. 订阅onNext被解雇
  5. 点击了刷新按钮
  6. obsSubject.onNext()调用
  7. map function throw error
  8. 进入捕捉功能
  9. 订阅onNext被解雇
  10. 点击了刷新按钮
  11. obsSubject.onNext()调用
  12. 无。我需要继续订阅
  13. 我的理解是catch应该保留订阅,但我的测试表明它没有。为什么呢?

1 个答案:

答案 0 :(得分:5)

根据评论中给出的上下文,您需要:

  • 每个刷新按钮都会触发' get results'
  • 要向用户显示的每个错误

你真的不需要重新订阅,它是一种反模式,因为Rx中的代码从不依赖于它,而额外的递归调用只会让读者感到困惑。它还提醒我们回调地狱。

在这种情况下,你应该:

  • 删除doSubscribe()调用,因为您不需要它们。使用该代码,您已经拥有了每次刷新点击都会触发新的“获得结果”的行为。
  • select().switch()替换为.flatMap()(或.flatMapLatest())。当您执行select()时,结果是元流(流的流),并且您正在使用switch()将元数据流展平为流。这就是flatMap所做的一切,但仅限于一次操作。您还可以将flatMap理解为JS Promises的.then()
  • 包含将处理您的错误的运算符.catch(),如catch块中所示。在发生错误后您无法获得更多结果的原因是,Observable始终会因错误或“完成”错误而终止。事件。使用catch()运算符,我们可以用Observable上的sane事件替换错误,以便它可以继续。

改善您的代码:

var refreshObs = $scope.$createObservableFunction('refresh');

refreshObs
  .flatMapLatest(function (x, idx, obs) {
    // get the results.
    // in here might throw an exception
    // should return an Observable of the results
  })
  .catch(function(e) {
      // do something with the error
      return Rx.Observable.empty(); // replace the error with nothing
  })
  .subscribe(function (x) { 
      // on next
  });

另请注意,我删除了onError和onComplete处理程序,因为它们内部没有任何操作。

另请参阅更多运营商。例如,retry()可用于自动获得结果'每次发生错误时都会再次出现见https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/retry.md

retry()do()结合使用以处理错误(do),并允许订阅者自动重新订阅源可观察量(retry)。

refreshObs
  .flatMapLatest(function (x, idx, obs) {
    // get the results.
    // in here might throw an exception
    // should return an Observable of the results
  })
  .do(function(){}, // noop for onNext
  function(e) {
      // do something with the error
  })
  .retry()
  .subscribe(function (x) { 
      // on next
  });

请参阅此处的工作示例:http://jsfiddle.net/staltz/9wd13gp9/9/