Utwórz jednorazową subskrypcję

182

Muszę utworzyć subskrypcję, Observablektóra jest usuwana natychmiast po pierwszym wywołaniu.

Czy jest coś takiego:

observable.subscribeOnce(func);

Mój przypadek użycia, tworzę subskrypcję w programie obsługi trasy ekspresowej, a subskrypcja jest wywoływana wiele razy na żądanie.

Berkeley Martinez
źródło

Odpowiedzi:

319

Nie jesteś w 100% pewien, czego potrzebujesz, ale jeśli chcesz obserwować tylko pierwszą wartość, użyj albo first()albo take(1):

observable.first().subscribe(func);

uwaga: .take(1)i .first()obaj anulują subskrypcję automatycznie, gdy ich warunek zostanie spełniony

Aktualizacja z RxJS 5.5+

Z komentarza Coderera .

import { first } from 'rxjs/operators'

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

Dlatego

Brandon
źródło
33
Czy subskrypcja zostanie automatycznie wyczyszczona po?
Berkeley Martinez
50
Tak. Weź i najpierw wypisz się, gdy ich warunek zostanie spełniony.
Brandon
20
Dlaczego w dokumentacji nie jest napisane, że automatycznie usuwa subskrypcję?
jzig
17
Jest to ogólna zasada RxJS, że subskrypcje są usuwane, gdy kończy się obserwowalny strumień. Oznacza to, że każdy operator, który „skraca” strumień (lub przekształca go w strumień innego typu), zrezygnuje z subskrypcji strumienia źródłowego po zakończeniu operacji. Nie jestem pewien, gdzie i czy jest to określone w dokumentacji.
Brandon
37
Jeśli ktoś przyjdzie do tego w 2018 roku, tak naprawdę chcesz observable.pipe(first()).subscribe(func), skąd firstpochodzi rxjs/operators.
Coderer,
32

RxJS ma jedną z najlepszych dokumentacji, z jaką kiedykolwiek się spotkałem. Podążanie za poniższym linkiem przeniesie Cię do niezwykle pomocnej tabeli mapującej przypadki użycia na operatory. Na przykład, w ramach programu „Chcę podjąć pierwszą wartość” przypadek użycia są trzy podmioty: first, firstOrDefault, i sample.

Uwaga, jeśli obserwowalna sekwencja zakończy się bez powiadomień, wówczas firstoperator powiadamia abonentów o błędzie, podczas gdy firstOrDefaultoperator podaje abonentom wartość domyślną.

wyszukiwanie przypadków użycia przez operatorów

DetweilerRyan
źródło
3

Jeśli chcesz wywołać Observable tylko raz, oznacza to, że nie będziesz czekać na strumień z niego. Więc używanie toPromise()zamiast tego subscribe()wystarczyłoby w twoim przypadku, ponieważ toPromise()nie wymaga rezygnacji z subskrypcji.

M Fuat NUROĞLU
źródło
bardzo interesujące, to również oznacza, że ​​możemy po prostu awaitto, promiseco czyni to jednym liniowcem
Louie Almeda
@LouieAlmeda, czy możesz podać jeden przykład?
Ado Ren
Cześć @AdoRen, wyjaśniłem tę technikę w odpowiedzi tutaj dla Ciebie, mam nadzieję, że to pomoże.
Louie Almeda
2

Aby uzupełnić odpowiedź @ Brandon , użycie first()lub podobne jest również niezbędne do aktualizacji BehaviorSubjectopartej na jej Observable. Na przykład (nieprzetestowane):

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
źródło
2

Czysta i wygodna wersja

Rozwijając niesamowitą odpowiedź M Fuat NUROĞLU na temat przekształcania tego, co obserwowalne w obietnicę, oto bardzo wygodna jej wersja.

const value = await observable.toPromise();

console.log(value)

Piękno tego polega na tym, że możemy użyć tej wartości jak normalnej zmiennej bez wprowadzania kolejnego zagnieżdżonego bloku!

Jest to szczególnie przydatne, gdy trzeba uzyskać wiele wartości z wielu obserwacji. Schludnie i czysto.

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

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

Oczywiście będziesz musiał wykonać swoją funkcję zawierającą, asyncjeśli chcesz iść tą trasą. Możesz także po prostu .thenobiecać, jeśli nie chcesz, aby funkcja zawierająca była asynchroniczna

Nie jestem pewien, czy istnieją kompromisy w tym podejściu, daj mi znać w komentarzach, abyśmy byli świadomi.

PS Jeśli podobała Ci się ta odpowiedź, nie zapomnij też zagłosować za odpowiedzią M Fuat NUROĞLU :)

Louie Almeda
źródło
0

Miałem podobne pytanie.

Poniżej został wezwany jeszcze później z różnych zmieniaczy stanu. Ponieważ nie chciałem.

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

Postanowiłem spróbować unsubscribe()po zasubskrybowaniu, jak poniżej.

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

subscribe(func).unsubscribe();jest jak subscribeOnce(func).

Mam nadzieję, że to też pomogło.

MrHIDEn
źródło