捕捉可观察对象之间的循环依赖 [英] Catch circular dependency between observables

查看:46
本文介绍了捕捉可观察对象之间的循环依赖的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用户编程场景,用户最终可以创建两个相互依赖的 observable.RxJS 不允许循环依赖,据我所知,内存或堆栈达到了它的极限,onError 回调被触发,值为 true.

如何显式检测循环依赖并抛出更具描述性的错误消息?

这段代码说明了如何在 RxJS 中创建循环依赖:

var obsA,obB;obsA = Rx.Observable.returnValue(42).combineLatest(obsB, 函数 (a, b) {返回 a + b;});obsB = Rx.Observable.returnValue(42).combineLatest(obsA, function (b, a) {返回 b + a;});obA.subscribe(函数(val){console.log('onNext:' + val);},功能(错误){console.error('onError: ' + err);},功能 () {console.log('onCompleted');});

错误信息很简单true.

解决方案

原始问题中的代码没有创建循环依赖.在您定义 ObsA 时,ObsBundefined,所以您真正所做的是调用 combineLatest(undefined, function ...).所以你看到的错误是因为你将 undefined 传递给 combinedLatest().

创建真正的循环依赖实际上需要一些努力.如果您使用 defer,那么您将拥有真正的循环依赖:

var obsA,obB,参考,参考;aRef = Rx.Observable.defer(function () {返回 obsA;});bRef = Rx.Observable.defer(function () {返回 obsB;});obsA = Rx.Observable.returnValue(42).combineLatest(bRef, function (a, b) {返回 a + b;});obsB = Rx.Observable.returnValue(42).combineLatest(aRef, function (b, a) {返回 b + a;});obsA.subscribe();

<script src='https://rawgit.com/Reactive-Extensions/RxJS/v.2.5.3/dist/rx.all.js'></script>

现在这是一个真正的循环依赖.不幸的是,您仍然会遇到相同的错误,尽管堆栈跟踪要深得多:

RangeError:超出最大调用堆栈大小./* ... 堆 ... */

没有万无一失的方法来检测周期.您可以将 observable 包装在一个新的 observable 中,并检测对 subscribe 方法的递归调用.但是,如果底层 observables 使用 subscribeOnpublishconcat 任何其他延迟实际循环订阅的东西,这样的算法就会失败.>

我的最佳建议是附加一个 catch 子句,用于检查范围错误并将其替换为更好的错误:

var obsA,obB,参考,参考;aRef = Rx.Observable.defer(function () {返回 obsA;});bRef = Rx.Observable.defer(function () {返回 obsB;});obsA = Rx.Observable.returnValue(42).combineLatest(bRef, function (a, b) {返回 a + b;}).catch(函数(e){var isStackError = e instanceof RangeError &&e.message === '超出最大调用堆栈大小';return Rx.Observable.throw(isStackError ? new Error('无效,可能是循环观察对象.') : e);});obsB = Rx.Observable.returnValue(42).combineLatest(aRef, function (b, a) {返回 b + a;}).catch(函数(e){var isStackError = e instanceof RangeError &&e.message === '超出最大调用堆栈大小';return Rx.Observable.throw(isStackError ? new Error('无效,可能是循环观察对象.') : e);});obsA.subscribe();

<script src='https://rawgit.com/Reactive-Extensions/RxJS/v.2.5.3/dist/rx.all.js'></script>

I have a user-programming scenario where user can end up creating two observables that depend on each other. RxJS does not allow circular dependencies, as far as I can see, the memory or stack reaches its limits and the onError callback is triggered with the value true.

How to detect the circular dependency explicitly and throw a more descriptive error message?

This codes illustrates how to create a circular dependency in RxJS:

var obsA,
    obsB;

obsA = Rx.Observable
    .returnValue(42)
    .combineLatest(obsB, function (a, b) {
        return a + b;
    });

obsB = Rx.Observable
    .returnValue(42)
    .combineLatest(obsA, function (b, a) {
        return b + a;
    });


obsA
    .subscribe(function (val) {
        console.log('onNext:' + val);
    },
    function (err) {
        console.error('onError: ' + err);
    },
    function () {
        console.log('onCompleted');
    });

The error message is simply true.

解决方案

The code in the original question does not create a circular dependency. At the time you define ObsA, ObsB is undefined and so what you've really done is call combineLatest(undefined, function ...). So the error you are seeing is because you are passing undefined to combinedLatest().

It actually takes some effort to create a real circular dependency. If you use defer, then you would have a true circular dependency:

var obsA,
    obsB,
    aRef,
    bRef;

aRef = Rx.Observable.defer(function () {
    return obsA;
});

bRef = Rx.Observable.defer(function () {
    return obsB;
});

obsA = Rx.Observable
    .returnValue(42)
    .combineLatest(bRef, function (a, b) {
            return a + b;
    });

obsB = Rx.Observable
    .returnValue(42)
    .combineLatest(aRef, function (b, a) {
        return b + a;
    });

obsA.subscribe();

<script src='https://rawgit.com/Reactive-Extensions/RxJS/v.2.5.3/dist/rx.all.js'></script>

Now that is a real circular dependency. Unfortunately you still get the same error, though with a much deeper stack trace:

RangeError: Maximum call stack size exceeded.
/* ... stack ... */

There is no fool-proof way to detect cycles. You could wrap the observables in a new observable and detect recursive calls to your subscribe method. But such an algorithm would be defeated if the underlying observables are using subscribeOn or publish or concat anything else that delays the actual circular subscriptions.

The best suggestion I have is to append a catch clause that checks for a range error and replaces it with a better error:

var obsA,
    obsB,
    aRef,
    bRef;

aRef = Rx.Observable.defer(function () {
    return obsA;
});

bRef = Rx.Observable.defer(function () {
    return obsB;
});

obsA = Rx.Observable
    .returnValue(42)
    .combineLatest(bRef, function (a, b) {
            return a + b;
    })
    .catch(function (e) {
        var isStackError = e instanceof RangeError && e.message === 'Maximum call stack size exceeded';
    
        return Rx.Observable.throw(isStackError ? new Error('Invalid, possibly circular observables.') : e);
    });

obsB = Rx.Observable
    .returnValue(42)
    .combineLatest(aRef, function (b, a) {
        return b + a;
    })
    .catch(function (e) {
        var isStackError = e instanceof RangeError && e.message === 'Maximum call stack size exceeded';
    
        return Rx.Observable.throw(isStackError ? new Error('Invalid, possibly circular observables.') : e);
    });

obsA.subscribe();

<script src='https://rawgit.com/Reactive-Extensions/RxJS/v.2.5.3/dist/rx.all.js'></script>

这篇关于捕捉可观察对象之间的循环依赖的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆