10

免责声明:它是先前安全更新 2 个依赖流问题的延续

在允许流不终止的 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's 这样的复合类型Data.Either并将其流式传输而不是标量双精度数。

想法?

UPD:是的,我已经阅读了在响应式扩展中处理异常而不停止序列,但我仍然希望有更好的方法。

4

2 回答 2

6

你真的有两个选择:

  1. 正如您所说,返回某种形式的Either结果可以是结果,也可以是错误。

由于这是 JavaScript,您显然不需要正式的类型,只需将 Error 实例与数字一起流式传输,您的订阅者可以通过检查接收到的值的运行时类型来区分它们。.catch(function (e) { return Rx.Observable.of(e); }所以这就像在你的调用之后添加一样简单.fromPromise(或者代替.promise(),使用.then()错误过滤器来产生一个承诺,当出现错误时,它将具有你想要的任何值)。

  1. 将错误发送到单独的流中。

基本上有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错误与错误分开,请创建 2 个主题in

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

于 2014-12-30T16:03:25.660 回答
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();
}
于 2014-12-24T16:44:17.060 回答