从流onError恢复的惯用方法

时间:2014-12-24 01:59:08

标签: javascript reactive-programming rxjs reactive-extensions-js

免责声明:这是之前Safe update for 2 dependent streams问题

的延续

什么是处理RxJS(或任何其他RX实现)中的错误的惯用方法,它允许流不终止?

相关代码

function convert(unit, value) {
    var request = {};
    request[unit] = value;

    var conversion = $.ajax({
        method: 'POST',
        url: './convert.php',
        data: request,
        dataType: 'json'
    }).promise();

    return Rx.Observable.fromPromise(conversion).takeUntil(inInput.merge(cmInput));
}

var cmElement = document.getElementById('cm'),
    inElement = document.getElementById('in');

var cmInput = Rx.Observable.fromEvent(cmElement, 'input').map(targetValue),
    inInput = Rx.Observable.fromEvent(inElement, 'input').map(targetValue);

var inches = cmInput
    .flatMap(convert.bind(null, 'cm'))
    .startWith(0);

var centimeters = inInput
    .flatMap(convert.bind(null, 'in'))
    .startWith(0);

因此,您可以看到我们使用输入字段更改流并将其传递给convert函数,该函数将其转换为另一个单元并进一步传递结果。

如果在$.ajax()调用期间出现错误,则会向上传播,整个inchescetimeters流停止(实际上是预期的)。

但是如何实现它呢?

这样我可以优雅地处理错误,比如显示错误消息,并在新数据到达时再试一次?

我目前的想法是引入一个像Haskell Data.Either这样的复合类型并将其流式传输而不是标量双精度。

思想?

UPD :是的,我看过Handling Exceptions in Reactive Extensions without stopping sequence,但我仍然希望有更好的方法。

2 个答案:

答案 0 :(得分:6)

你真的有两个选择:

  1. 正如您所说,返回某种形式的Either,可能是结果或错误。
  2. 由于这是JavaScript,您显然不需要正式类型,只能将错误实例与数字一起流式传输,并且您的订阅者可以通过检查接收到的值的运行时类型来区分它们何时接收它们。这就像在.catch(function (e) { return Rx.Observable.of(e); }调用之后添加.fromPromise一样简单(或者代替.promise(),使用带有错误过滤器的.then()来生成一个具有任何价值的承诺想要有错误的时候。)

    1. 在单独的信息流中发送错误。
    2. 基本上convert有另一个参数,它应该用来发出错误的观察者:

      function convert(errorObserver, unit, value) {
          ...
          return Rx.Observable
              .fromPromise(conversion)
              .catch(function (e) {
                  errorObserver.onNext(e); // or whatever you want to emit here
                  return Rx.Observable.empty(); // or possibly Rx.Observable.of(0) to reset?
              })
              ...
      }
      

      然后只需为您的错误流创建一个Subject,并将其作为convert的第一个参数提供。如果您希望cm错误与in错误分开,请创建2个主题。

      我个人倾向于使用第一种方法。

答案 1 :(得分:0)

您只需将一个catch()添加到fromPromise()链

即可
    return Rx.Observable.fromPromise(conversion).catch(handleError).takeUntil(inInput.merge(cmInput));

function handleError() {
    //Do whatever you want to handle this exception then return empty.
    return Rx.Observable.Empty();
}