rxjs只在订阅时使用promise一次

时间:2016-03-11 08:24:41

标签: javascript promise rxjs

我想第一次使用rxjs,但我有点被卡住了,因为它的行为并不像我想要的那样:在我的场景中,我想创建一个可观察的一个承诺。但我希望承诺只被调用一次(不是每次订阅),我希望它不会在创建时被调用(将调用推迟到第一个订阅)。

首先我尝试了这个:

var source = Rx.Observable.fromPromise(_this.getMyPromise())

导致在创建时调用getMyPromise函数。这并不令人满意,因为那时候我还不知道是否真的会使用这个来源。

然后我尝试了:

var source = Rx.Observable.defer(function() { return _this.getMyPromise() })

每次对源进行新订阅时都会调用getMyPromise函数。这会对Web服务器进行太多不必要的调用。 Rx.Observable.create函数似乎也有同样的问题。

那剩下的是什么,或者我错过了什么?

2 个答案:

答案 0 :(得分:6)

.shareReplay()这样做,例如:

var source = Rx.Observable.defer(function() { return _this.getMyPromise() }).shareReplay();

如果您使用的是rxjs5,则需要阅读:Pattern for shareReplay(1) in RxJS5

在回答下面的评论时,我可以想到对上述逻辑的一个相当直接的扩展,它会做你想要的,但它有一个警告。假设您要用来触发“刷新”的事件在流s $中表示,那么您可以执行以下操作:

var source = Rx.Observable.of({}).concat(s$)
    .flatMapLatest(function() {
        return Rx.Observable.defer(function() {
            return _this.getMyPromise()
        })
    })
    .shareReplay(1)

我们这里有一个以虚拟对象开头的流来开始滚动,然后是一个由刷新事件组成的流。这些中的每一个都被投射到一个新的observable中,该observable是通过对getMyPromise方法的全新调用创建的,并且整个过程被展平为单个流。最后,我们保留shareReplay逻辑,这样我们才能在应该的时候实际调用。

需要注意的是,只有在始终至少有一个订阅者来源时才能正常工作(在处置完所有其他订阅之后的第一个订阅将再次运行promise,并且将同时接收先前缓存的值和结果它导致的承诺)。

答案 1 :(得分:0)

以下是一个答案,使用简单的帮助程序始终不需要至少一个订阅者:

var _p = null;
var once = function() { return _p || (_p = _this.getMyPromise());

var source = Rx.Observable.defer(once);

或者如果你正在使用lodash,你可以_.memoize getMyPromise自动获取此内容。