Crea un abbonamento unico


182

Devo creare un abbonamento a un servizio Observableche viene immediatamente eliminato quando viene chiamato per la prima volta.

C'è qualcosa come:

observable.subscribeOnce(func);

Nel mio caso d'uso, sto creando un abbonamento in un gestore di route espresso e l'abbonamento viene chiamato più volte per richiesta.

Risposte:


319

Non sei sicuro al 100% di ciò di cui hai bisogno, ma se vuoi solo osservare il primo valore, usa uno first()o take(1):

observable.first().subscribe(func);

nota: .take(1)ed .first()entrambi annullano l'iscrizione automaticamente quando le loro condizioni sono soddisfatte

Aggiornamento da RxJS 5.5+

Dal commento di Coderer .

import { first } from 'rxjs/operators'

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

Ecco perché


33
L'abbonamento viene automaticamente ripulito dopo?
Berkeley Martinez,

50
Sì lo fa. Prendi e prima annulla entrambi l'iscrizione quando le loro condizioni sono soddisfatte.
Brandon,

20
Perché la documentazione non dice che elimina automaticamente l'abbonamento?
jzig,

17
È una regola RxJS generale che le sottoscrizioni vengono eliminate al termine di un flusso osservabile. Ciò significa che qualsiasi operatore che "accorcia" uno stream (o lo trasforma in un diverso tipo di stream) annulla l'iscrizione allo stream di origine al termine dell'operazione. Non sono sicuro di dove o se ciò sia indicato nella documentazione.
Brandon,

37
Se qualcuno arriva nel 2018, in realtà vuoi observable.pipe(first()).subscribe(func), da dove firstviene rxjs/operators.
Coderer,

32

RxJS ha alcuni dei migliori documenti che abbia mai incontrato. Seguire il seguente link vi porterà a una tabella estremamente utile per mappare i casi d'uso agli operatori. Per esempio, sotto il "Voglio prendere il primo valore" caso d'uso sono tre operatori: first, firstOrDefault, e sample.

Nota, se una sequenza osservabile si completa senza notifiche, l' firstoperatore notifica agli abbonati un errore mentre l' firstOrDefaultoperatore fornisce un valore predefinito agli abbonati.

ricerca caso d'uso dell'operatore


3

Se si desidera chiamare un osservabile solo una volta, significa che non si attende un flusso da esso. Quindi utilizzare al toPromise()posto di subscribe()sarebbe sufficiente nel tuo caso in quanto toPromise()non è necessario annullare l'iscrizione.


molto interessante, anche questo significa che può solo awaitil promiseche lo rende uno di linea
Louie Almeda

@LouieAlmeda potresti darci un esempio di copertina?
Ado Ren,

Ciao @AdoRen, ho esposto la tecnica in una risposta qui per te, spero che ti aiuti.
Louie Almeda,

2

Per integrare la risposta di @ Brandon , utilizzare first()o simili è anche essenziale per aggiornare un BehaviorSubjectbasato sulla sua Observable. Ad esempio (non testato):

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);
  });

2

Versione pulita e conveniente

Espandendo su M Fuat la straordinaria risposta di NUROĞLU sulla conversione dell'osservabile in una promessa, ecco la versione molto conveniente di essa.

const value = await observable.toPromise();

console.log(value)

Il bello di questo è che possiamo usare quel valore come una normale variabile senza introdurre un altro blocco nidificato!

Ciò è particolarmente utile quando è necessario ottenere più valori da più osservabili. Ordinato e pulito.

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

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

Ovviamente, dovrai fare la tua funzione di contenimento asyncse vuoi seguire questa rotta. Puoi anche solo .thenpromettere se non vuoi che la funzione contenitrice sia asincrona

Non sono sicuro che ci siano compromessi con questo approccio, non esitate a farmelo sapere nei commenti, quindi siamo consapevoli.

PS Se ti è piaciuta questa risposta, non dimenticare di votare anche la risposta di M Fuat NUROĞLU :)


0

Ho avuto una domanda simile.

Di seguito fu chiamato anche più tardi da diversi cambiavalute statali. Come non volevo.

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

Ho deciso di provare unsubscribe()dopo l'abbonamento come di seguito.

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

subscribe(func).unsubscribe();è come subscribeOnce(func).

Spero che anche questo ti abbia aiutato.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.