创建一个只执行源一次的惰性缓存observable

时间:2017-01-14 22:43:41

标签: javascript rxjs rxjs5

我正在尝试使用rxjs observable委托,但在应用程序的整个生命周期内共享一段昂贵的工作。

基本上,如:

var work$ = Observable.create((o) => {
  const expensive = doSomethingExpensive();
  o.next(expensive);
  observer.complete();
})
.publishReplay(1)
.refCount();

现在,这样做很好,完全符合我的要求,除了一件事:如果所有订阅者都取消订阅,那么当下一个订阅时,我的昂贵工作又会发生。我想保留它。

现在,我可以使用主题,或者我可以删除refCount()并手动使用连接(并且永远不会断开连接)。但是,这会使昂贵的工作在我连接的那一刻发生,而不是用户第一次尝试消耗工作$。

基本上,我想要类似于refCount的东西,它只查看第一个连接订阅,并且永远不会断开连接。一个“懒惰的连接”。

这样的事情是否可能?

1 个答案:

答案 0 :(得分:3)

publishReplay()如何实际运作

它在内部创建ReplaySubject并使multicast兼容。 ReplaySubject的最小重放值是1发射。这导致以下结果:

  • 首次订阅将触发publishReplay(1)内部订阅源流并通过ReplaySubject管道所有排放,有效缓存最后 n (= 1)排放< / LI>
  • 如果在源仍处于活动状态时启动了第二个订阅,multicast()会将我们连接到同一个replaySubject,我们将在源流完成之前收到所有下一个排放。
  • 如果在源已完成后启动订阅,则replaySubject已缓存最后的 n 排放,并且只会在完成之前收到这些订阅。

const source = Rx.Observable.from([1,2])
  .mergeMap(i => Rx.Observable.of('emission:'+i).delay(i * 100))
  .do(null,null,() => console.log('source stream completed'))
  .publishReplay(1)
  .refCount();

// two subscriptions which are both in time before the stream completes
source.subscribe(val => console.log(`sub1:${val}`), null, () => console.log('sub1 completed'));
source.subscribe(val => console.log(`sub2:${val}`), null, () => console.log('sub2 completed'));

// new subscription after the stream has completed already
setTimeout(() => {
  source.subscribe(val => console.log(`sub_late-to-the-party:${val}`), null, () => console.log('sub_late-to-the-party completed'));
}, 500);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.0.3/Rx.js"></script>