[英]How can I achieve a shareReplay with reconnection?
In the following code, I create a simple observable that produces one value and then complete.在下面的代码中,我创建了一个简单的 observable,它产生一个值然后完成。 Then I share that observable replaying the last item and suscribe 3 times.
然后我分享那个 observable 重放最后一个项目并订阅 3 次。 The first right after, the second one before the value is produced and the third time after value is produced and the observable has completed.
第一次紧随其后,第二次在产生价值之前,第三次在价值产生并且 observable 完成之后。
let i = 0;
let obs$ = Rx.Observable.create(obs => {
console.log('Creating observable');
i++;
setTimeout(() => {
obs.onNext(i);
obs.onCompleted();
}, 2000);
}).shareReplay(1);
obs$.subscribe(
data => console.log(`s1: data = ${data}`),
() => {},
() => console.log('finish s1')
);
setTimeout( () => {
obs$.subscribe(
data => console.log(`s2: data = ${data}`),
() => {},
() => console.log('finish s2')
);
}, 1000);
setTimeout( () => {
obs$.subscribe(
data => console.log(`s3: data = ${data}`),
() => {},
() => console.log('finish s3')
);
}, 6000);
You can execute this on jsbin你可以在jsbin上执行这个
This results in the following marble diagram这导致以下大理石图
Actual
s1: -----1$
s2: \--1$
s3: \1$
But I would expect但我希望
Expected
s1: -----1$
s2: \--1$
s3: \----2$
I can understand why someone would like to have the first behaviour, but my reasoning is that, unlike this example, where I'm returning a number, I could be returning an object susceptible to unsubscribe behaviour, for example a database connection.我可以理解为什么有人想要第一个行为,但我的推理是,与这个例子不同,我返回一个数字,我可能返回一个易受取消订阅行为影响的对象,例如数据库连接。 If the above marble diagram represents a database connection, where in the dispose method I call a
db.close()
, on the third subscription I would have an exception, because I'm receiving as value a database handler that was released.如果上面的弹珠图表示一个数据库连接,在 dispose 方法中我调用了
db.close()
,那么在第三个订阅中我会有一个例外,因为我收到的值是一个已发布的数据库处理程序。 (because when the second subscription finished refCount = 0 and the source is disposed). (因为当第二个订阅完成时 refCount = 0 并且源被释放)。
Also another weird thing this example has, is that even it's resolving with the first value and completing just after, its subscribing to the source twice (as you can see by the duplicated "Creating observable")这个例子还有另一个奇怪的事情是,即使它用第一个值解析并在之后完成,它订阅源两次(正如你在重复的“Creating observable”中看到的那样)
I know this github issue talks about this but what I'm missing is:我知道这个 github 问题谈到了这个,但我缺少的是:
How can achieve (both in RxJs4 and 5) a shared observable that can replay the last item if the source observable hasn't completed, and if its done (refCount = 0), recreate the observable.如何实现(在 RxJs4 和 5 中)共享的 observable,如果源 observable 尚未完成,则可以重放最后一项,如果完成(refCount = 0),则重新创建 observable。
In RxJs5 I think the share method solves the reconnecting part of my problem, but not the sharing part.在 RxJs5 中,我认为 share 方法解决了我问题的重新连接部分,但不能解决共享部分。
In RxJs4 I'm clueless在 RxJs4 我一无所知
If possible I would like to solve this using existing operators or subjects.如果可能的话,我想使用现有的运算符或主题来解决这个问题。 My intuition tells me I would have to create a different Subject with such logic, but I'm not quite there yet.
我的直觉告诉我我必须用这样的逻辑创建一个不同的主题,但我还没有完全到位。
shareReplay
keeps the same underlying ReplaySubject
instance for the rest of the lifetime of the returned observable. shareReplay
在返回的 observable 的剩余生命周期中保持相同的底层ReplaySubject
实例。
Once ReplaySubject
completes, you can't put any more values into it, but it will still replay.一旦
ReplaySubject
完成,您就不能ReplaySubject
任何值,但它仍会重播。 So...所以...
i
from 0
to 1
.i
从0
增加到1
。onNext(i)
, then onCompleted()
.onNext(i)
,然后是onCompleted()
。onCompleted()
signal completes the ReplaySubject
inside the shareReplay
, meaning that from now on, that shared observable will simply replay the value it has (which is 1) and complete. onCompleted()
信号完成了ReplaySubject
的shareReplay
,这意味着从现在开始,共享的 observable 将简单地重放它所拥有的值(即 1)并完成。 Another, separate issue is that since you shared the observable, it's only ever going to call the subscriber function one time .另一个单独的问题是,由于您共享了 observable,它只会调用一次订阅者函数。 That means that
i
will only ever be incremented one time.这意味着
i
只会增加一次。 So even if you didn't onCompleted
and kill your underlying ReplaySubject
, you're going to end up not incrementing it to 2
.因此,即使您没有
onCompleted
并杀死您的底层ReplaySubject
,您最终也不会将其增加到2
。
A quick way to tell is onNext
vs next
.一个快速判断的方法是
onNext
与next
。 You're currently using RxJS 4 in your example, but you've tagged this with RxJS 5, and you've sighted an issue in RxJS 5. RxJS 5 is beta and a new version that is a complete rewrite of RxJS 4. The API changes were done mostly to match the es-observable proposal which is currently at stage 1您当前在示例中使用的是 RxJS 4,但是您已经用 RxJS 5 标记了它,并且您在 RxJS 5 中发现了一个问题。RxJS 5 是测试版,是一个完全重写 RxJS 4 的新版本。 API 更改主要是为了匹配目前处于第 1 阶段的es-observable 提案
I've updated your example to give you your expected results我已经更新了您的示例,以便为您提供预期的结果
Basically, you want to use a shared version of the observable for the first two calls, and the original observable for the third one.基本上,您希望在前两次调用中使用共享版本的 observable,在第三次调用中使用原始 observable。
let i = 0;
let obs$ = Rx.Observable.create(obs => {
console.log('Creating observable');
i++;
setTimeout(() => {
obs.onNext(i);
obs.onCompleted();
}, 2000);
})
let shared$ = obs$.shareReplay(1);
shared$.subscribe(
data => console.log(`s1: data = ${data}`),
() => {},
() => console.log('finish s1')
);
setTimeout( () => {
shared$.subscribe(
data => console.log(`s2: data = ${data}`),
() => {},
() => console.log('finish s2')
);
}, 1000);
setTimeout( () => {
obs$.subscribe(
data => console.log(`s3: data = ${data}`),
() => {},
() => console.log('finish s3')
);
}, 6000);
Also, protip: be sure to return a cancellation semantic for your custom observable that calls clearTimeout
.另外,提示:确保为调用
clearTimeout
自定义 observable 返回取消语义。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.