Créer un abonnement unique

182

Je dois créer un abonnement à un Observablequi est immédiatement supprimé lors de son premier appel.

Y a-t-il quelque chose comme:

observable.subscribeOnce(func);

Mon cas d'utilisation, je crée un abonnement dans un gestionnaire d'itinéraire express et l'abonnement est appelé plusieurs fois par demande.

Berkeley Martinez
la source

Réponses:

319

Vous n'êtes pas sûr à 100% de ce dont vous avez besoin, mais si vous ne voulez observer que la première valeur, utilisez soit first()ou take(1):

observable.first().subscribe(func);

note: .take(1)et les .first()deux se désabonnent automatiquement lorsque leur condition est remplie

Mise à jour à partir de RxJS 5.5+

D'après le commentaire de Coderer .

import { first } from 'rxjs/operators'

observable
  .pipe(first())
  .subscribe(func);

Voici pourquoi

Brandon
la source
33
L'abonnement est-il automatiquement nettoyé après?
Berkeley Martinez
50
Oui. Prenez d'abord les deux désabonnement lorsque leur condition est remplie.
Brandon
20
Pourquoi la documentation ne dit-elle pas qu'elle supprime automatiquement l'abonnement?
jzig
17
C'est une règle générale RxJS selon laquelle les abonnements sont supprimés à la fin d'un flux observable. Cela signifie que tout opérateur qui "raccourcit" un flux (ou le transforme en un type de flux différent) se désabonnera du flux source une fois son opération terminée. Je ne sais pas où ni si cela est indiqué dans la documentation.
Brandon
37
Si quelqu'un vient à cela en 2018, vous voulez vraiment observable.pipe(first()).subscribe(func), d'où firstvient rxjs/operators.
Coderer
32

RxJS possède la meilleure documentation que j'ai jamais rencontrée. En suivant le lien ci-dessous, vous accédez à un tableau extrêmement utile de cas d'utilisation de mappage de tableaux avec les opérateurs. Par exemple, sous le « Je veux prendre la première valeur » cas d'utilisation sont trois opérateurs: first, firstOrDefaultet sample.

Notez que si une séquence observable se termine sans aucune notification, alors l' firstopérateur avertit les abonnés avec une erreur tandis que l' firstOrDefaultopérateur fournit une valeur par défaut aux abonnés.

recherche de cas d'utilisation d'opérateur

DetweilerRyan
la source
3

Si vous souhaitez appeler un Observable une seule fois, cela signifie que vous n'attendrez pas un flux de celui-ci. Donc, utiliser à la toPromise()place de subscribe()serait suffisant dans votre cas car il toPromise()n'est pas nécessaire de se désinscrire.

M Fuat NUROĞLU
la source
très intéressant, cela signifie aussi que nous pouvons juste awaitce promisequi en fait une doublure
Louie Almeda
@LouieAlmeda pourrais-tu nous donner un exemple en une seule ligne?
Ado Ren
Salut @AdoRen, j'ai expliqué la technique dans une réponse ici pour vous, j'espère que cela vous aidera.
Louie Almeda le
2

Pour compléter la réponse de @ Brandon , l'utilisation first()ou autre est également essentielle pour mettre à jour un BehaviorSubjectbasé sur son Observable. Par exemple (non testé):

var subject = new BehaviorSubject({1:'apple',2:'banana'});
var observable = subject.asObservable();

observable
  .pipe(
    first(), // <-- Ensures no stack overflow
    flatMap(function(obj) {
      obj[3] = 'pear';
      return of(obj);
    })
  )
  .subscribe(function(obj) {
    subject.next(obj);
  });
Andy
la source
2

Version propre et pratique

En développant la réponse étonnante de M Fuat NUROĞLU sur la conversion de l'observable en promesse, voici la version très pratique de celle-ci.

const value = await observable.toPromise();

console.log(value)

La beauté de ceci est que nous pouvons utiliser cette valeur comme une variable normale sans introduire un autre bloc imbriqué!

Ceci est particulièrement pratique lorsque vous devez obtenir plusieurs valeurs à partir de plusieurs observables. Propre et net.

const content = await contentObservable.toPromise();
const isAuthenticated = await isAuthenticatedObservable.toPromise();

if(isAuthenticated){
   service.foo(content)
}

Bien sûr, vous devrez faire votre fonction contenant asyncsi vous voulez suivre cette route. Vous pouvez également simplement .thenla promesse si vous ne voulez pas que la fonction contenant soit asynchrone

Je ne sais pas s'il y a des compromis avec cette approche, n'hésitez pas à me le faire savoir dans les commentaires afin que nous en soyons conscients.

PS Si vous avez aimé cette réponse, n'oubliez pas de voter également pour la réponse de M Fuat NUROĞLU :)

Louie Almeda
la source
0

J'avais une question similaire.

Ci-dessous a été appelé même plus tard par différents changeurs d'État. Comme je ne voulais pas.

function foo() {
    // this was called many times which was not needed
    observable.subscribe(func);
    changeObservableState("new value");
}

J'ai décidé d'essayer unsubscribe()après m'être abonné comme ci-dessous.

function foo() {
    // this was called ONE TIME
    observable.subscribe(func).unsubscribe();
    changeObservableState("new value");
}

subscribe(func).unsubscribe();est comme subscribeOnce(func).

J'espère que cela vous a aidé aussi.

MrHIDEn
la source