RXJS 在订阅时仅使用一次承诺

rxjs using promise only once on subscribe

本文关键字:承诺 一次 RXJS      更新时间:2023-09-26

我想第一次使用rxjs,但有点卡住了,因为它的行为与我想要的并不完全相同:在我的场景中,我想从承诺创建一个可观察量。但是我希望承诺只调用一次(不是在每个订阅上),并且我不希望在创建时调用它(将调用推迟到第一个订阅)。

首先我尝试了这个:

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

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

然后我尝试了:

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

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

那么还剩下什么或我错过了什么?

.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)

我们在这里有一个流,从一个虚拟对象开始,让事情滚动,然后是一个由刷新事件组成的流。其中每一个都被投影到一个新的可观察量中,该可观察量由对 getMyPromise 方法的新调用创建,并且整个事情被平展为单个流。最后,我们保留 shareReplay 逻辑,因此我们只在应该调用的时候进行调用。

需要注意的是,仅当源始终至少有一个订阅者时,此操作才能正常工作(释放所有其他订阅后的第一个订阅将再次运行承诺,并将接收以前缓存的值和它导致运行的承诺的结果)。

这是一个答案,它不需要始终使用简单的帮助程序在源中至少有一个订阅者:

var _p = null;
var once = function() { return _p || (_p = _this.getMyPromise());
var source = Rx.Observable.defer(once);

或者,如果您使用的是 lodash,您可以_.memoize您的getMyPromise并自动获取它。