我有一个用户编程场景,用户最终可以创建两个相互依赖的observable。 RxJS不允许循环依赖,据我所知,内存或堆栈达到了极限,onError
回调是用值true
触发的。
如何显式检测循环依赖项并抛出更具描述性的错误消息?
此代码说明了如何在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');
});
错误消息只是true
。
答案 0 :(得分:2)
原始问题中的代码不会创建循环依赖项。在您定义ObsA
时,ObsB
为undefined
,所以您真正做的就是致电combineLatest(undefined, function ...)
。因此,您看到的错误是因为您将undefined
传递给combinedLatest()
。
实际上需要花费一些精力来创建一个真正的循环依赖。如果你使用defer
,那么你将拥有一个真正的循环依赖:
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>
现在这是一个真正的循环依赖。不幸的是,你仍然会得到相同的错误,尽管有更深的堆栈跟踪:
RangeError: Maximum call stack size exceeded.
/* ... stack ... */
没有万无一失的方法来检测周期。您可以将observable包装在一个新的observable中,并检测对subscribe方法的递归调用。但是,如果基础可观察量使用subscribeOn
或publish
或concat
延迟实际循环订阅的任何其他内容,则此算法将被取消。
我最好的建议是附加一个catch
子句来检查范围错误,并用更好的错误替换它:
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>