我希望能够更好地了解主题与弹性运算符一起使用时的预期行为,即retry和retryWhen。
以下代码示例与它们的JSBin对应物(在示例链接中找到)略有不同,因为我使用箭头函数和类型以便于使用,这是使用版本4.0.0 - 4.0.7
我的预期弹性行为可以用以下example表示:
Rx.Observable
.interval(1000)
.flatMap( (count:number) => {
return count === 4 ? Rx.Observable.throw('Break') : Rx.Observable.return(count);
})
.retry()
.take(5);
Output
// 0
// 1
// 2
// 3
// 0 <-- Retry means we start again from scratch (expected)
到目前为止,一切都是一致的,即在第四个通知发生错误之后整个流从头开始重新启动(无状态架构的胜利)。
如果我们添加一个多播运算符并且在这样做时添加一个基础主题(在我的例子中是一个缓冲区为1的ReplaySubject)example:
const consumer : Rx.Observable<number> = Rx.Observable
.interval(1000)
.flatMap( (count:number) => {
return count === 4 ? Rx.Observable.throw('Break') : Rx.Observable.return(count);
})
.shareReplay(1) /* multicast(new Rx.ReplaySubject(1)).refCount() */
.retry()
.take(5);
const firstSubscriber : Rx.Disposable = consumer.subscribe( (next:number) => {
console.log('first subscriber: ' + next);
});
setTimeout(() => {
firstSubscriber.dispose(); /* Lets start fresh in that refCount === 0 */
const secondSubscriber : Rx.Disposable = consumer.subscribe( (next) => {
console.log('second subscriber: ' + next);
});
}, 5000 );
Output (before error is thrown)
// "first subscriber: 0"
// "first subscriber: 1"
// "first subscriber: 2"
// "first subscriber: 3"
Output (after error is thrown)
// "first subscriber: 3"
// "second subscriber: 3"
// "second subscriber: 3"
// "second subscriber: 3"
// "second subscriber: 3"
// "second subscriber: 3"
快速查看Subject标识何时出现错误,主题被标记为inError,并且每个将来的订阅者将获得最后一个通知(第46行)并在调用onError之后直接获得(第50行) )。
那么这会给我们留下什么?在我看来,我不相信你可以使用弹性运算符,当它跟随包含主题的任何其他运算符(shareReplay,发布等...)时。
此时我认为使用此设计取得成功的唯一方法是确保何时发生错误并处理节点,无论何时使用某个主题,都需要创建一个新主题(并且在兔子身上)我们开始走洞了吗?
multicast可以使用工厂/ subjectSelector:
.multicast( () => new Rx.ReplaySubject(1), (source:Rx.ConnectableObservable) => source );
如果您使用subjectSelector而不是直接为每个新订阅直接传入主题,请查看source,将调用subjectSelector并创建一个新的ConnectableObservable(第11行)。
此时我不确定是否共享(通过某些缓存)和处理(当检测到错误时)主题实际上会给订阅者多播?
在达到这一点时,我还编写了一个RecoverableReplaySubject,我在处置时已经取出了错误状态,这更多的是用于测试,并且期望RxJS团队将这个工作流程放在有充分理由。
非常感谢有关此主题的任何指导和经验。
谢谢
答案 0 :(得分:0)
shareReplay
主题在错误和完成方面持有不同的语义。例如,即使基础observable已完成(refCount == 0
),shareReplay
也不会完成,因此进一步调用它将产生(重放)过去的值。参看jsbin(shareReplay)与jsbin(分享)。
var source = Rx.Observable
.interval(100)
.take(5)
.shareReplay()
var first = source.subscribe( function(next) {
console.log('first subscriber: ' + next);
});
setTimeout(function() {
// first.dispose();
var second = source.subscribe( function(next) {
console.log('second subscriber: ' + next);
});
}, 1000 );
否则,您会找到关于shareReplay
(讨论您的问题)与其他运营商的行为的解释:
jhusain commented on Nov 4, 2015
开始)提出的解决方案恰恰是为多播运营商使用工厂功能。无论如何,尝试新设计并看它是否有效应该不会太难。