Rxjs utilise une seule fois lors de la souscription

Je voulais utiliser rxjs pour la première fois, mais je suis un peu bloqué car il ne se comporte pas comme je le veux: dans mon scénario, je veux créer une promesse observable. Mais je veux que la promesse ne soit appelée qu'une fois (pas sur chaque abonnement) et je veux qu'elle ne soit pas appelée au moment de la création (reportez l'appel à la première souscription).

D'abord, j'ai essayé ceci:

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

Ce qui provoque un appel à la fonction getMyPromise juste au moment de la création. Ce n'est pas satisfaisant parce qu'à ce moment-là, je ne sais pas si la source sera vraiment utilisée.

Ensuite, j'ai essayé:

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

Ce qui provoque un appel à la fonction getMyPromise chaque fois qu'un nouvel abonnement est effectué sur la source. Cela rend trop d'appels inutiles sur le serveur Web. La fonction Rx.Observable.create semble avoir le même problème.

Alors, qu'est-ce qui reste ou que me manque-t-il?

.shareReplay() fait ceci, par exemple:

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

Si vous utilisez rxjs5, vous voudrez lire: Pattern for shareReplay (1) dans RxJS5

En réponse à votre commentaire ci-dessous, je peux penser à une extension assez simple à la logique ci-dessus qui fera ce que vous voulez, mais il a une mise en garde. Disons que les événements que vous souhaitez utiliser pour déclencher un "rafraîchissement" sont représentés dans un flux, s $, alors vous pouvez faire quelque chose comme:

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

Ce que nous avons ici est un flux commençant par un objet fictif pour faire avancer les choses, suivi d'un flux composé de vos événements de rafraîchissement. Chacun d'entre eux est projeté dans un nouvel observable créé à partir d'une nouvelle invocation de votre méthode getMyPromise, et l'ensemble est aplati dans un flux unique. Enfin, nous gardons la logique shareReplay, alors nous ne faisons que des appels lorsque nous devrions.

La mise en garde est que cela ne fonctionnera correctement que s'il y a toujours au moins un abonné à la source (la première souscription après que tous les autres sont disposés sera à nouveau promulguée et recevra à la fois la valeur précédemment mise en cache et le résultat de la promesse Causé à courir).

Voici une réponse qui ne nécessite pas au moins un abonné à la source en tout temps en utilisant un assistant simple:

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

Ou si vous utilisez lodash, vous pouvez _.memoize votre getMyPromise et l'obtenir automatiquement.