Temat vs zachowanie Temat vs Powtórka Temat w Angular


124

Chciałem zrozumieć te 3:

Temat , temat zachowania i temat powtórki . Chciałbym ich używać i wiedzieć, kiedy i dlaczego, jakie są korzyści z ich używania i chociaż przeczytałem dokumentację, obejrzałem tutoriale i przeszukałem google, nie udało mi się tego zrozumieć.

Więc jaki jest ich cel? Najbardziej ceniona byłaby rzeczywista obudowa, która nie musi nawet kodować.

Wolałbym jasne wyjaśnienie, a nie tylko „a + b => c jesteś subskrybentem ....”

Dziękuję Ci


1
Jest już pytanie dotyczące zachowania z obserwowalnymi; stackoverflow.com/questions/39494058/ ... a dokumentacja na temat powtórki jest przejrzysta imo github.com/Reactive-Extensions/RxJS/blob/master/doc/api/…
eko

W tej odpowiedzi jest stosunkowo dokładna prezentacja tematów w Rxjs , co ładnie uzupełnia odpowiedź z peeksilet. Obejmuje to również ważne szczegóły dotyczące zachowania po rozwiązaniu umowy, więc warto się przyjrzeć.
user3743222

Odpowiedzi:


278

To naprawdę sprowadza się do zachowania i semantyki. Z

  • Subject- subskrybent otrzyma tylko opublikowane wartości, które zostały wyemitowane po subskrypcji. Zadaj sobie pytanie, czy tego chcesz? Czy subskrybent musi wiedzieć cokolwiek o poprzednich wartościach? Jeśli nie, możesz tego użyć, w przeciwnym razie wybierz jedną z pozostałych. Na przykład z komunikacją między komponentami. Załóżmy, że masz komponent, który publikuje zdarzenia dla innych komponentów po kliknięciu przycisku. Możesz skorzystać z usługi z tematem do komunikacji.

  • BehaviorSubject- ostatnia wartość jest buforowana. Abonent otrzyma najnowszą wartość przy pierwszej subskrypcji. Semantyka tego przedmiotu polega na przedstawieniu wartości, która zmienia się w czasie. Na przykład zalogowany użytkownik. Początkowy użytkownik może być użytkownikiem anonimowym. Ale gdy użytkownik się zaloguje, nową wartością jest stan uwierzytelnionego użytkownika.

    BehaviorSubjectInicjowany jest z wartością początkową. Czasami jest to ważne dla preferencji kodowania. Powiedz na przykład, że inicjalizujesz go za pomocą pliku null. Następnie w swojej subskrypcji musisz sprawdzić zerową wartość. Może OK, a może denerwujące.

  • ReplaySubject- może buforować do określonej liczby emisji. Wszyscy subskrybenci otrzymają wszystkie wartości zapisane w pamięci podręcznej po subskrypcji. Kiedy potrzebujesz takiego zachowania? Szczerze mówiąc, nie miałem potrzeby takiego zachowania, z wyjątkiem następującego przypadku:

    Jeśli zainicjujesz a ReplaySubjectz rozmiarem bufora 1, to w rzeczywistości zachowuje się tak jak a BehaviorSubject. Ostatnia wartość jest zawsze buforowana, więc zachowuje się jak wartość zmieniająca się w czasie. Dzięki temu nie ma potrzeby nullsprawdzania, jak w przypadku BehaviorSubjectinicjalizacji z rozszerzeniem null. W tym przypadku żadna wartość nie jest wysyłana do subskrybenta aż do pierwszej publikacji.

Tak więc naprawdę sprowadza się to do zachowania, którego oczekujesz (od tego, którego użyć). W większości przypadków prawdopodobnie będziesz chciał użyć a, BehaviorSubjectponieważ to, co naprawdę chcesz reprezentować, to semantyczna „wartość w czasie”. Ale ja osobiście nie widzę nic złego w zamianie ReplaySubjectinicjalizacji na 1.

To, czego chcesz uniknąć, to używanie wanilii, Subjectgdy naprawdę potrzebujesz zachowania pamięci podręcznej. Weźmy na przykład piszesz strażnika uciekającego lub rozwiązanie. Pobierasz dane z tej warty i ustawiasz je w usłudze Subject. Następnie w komponencie kierowanym subskrybujesz temat usługi, aby spróbować uzyskać wartość, która została wyemitowana w strażniku. OOP. Gdzie jest wartość? To już było wyemitowane, DUH. Użyj tematu "buforowania"!

Zobacz też:


1
To jest krótkie i łatwe do zrozumienia różnic. Gdy wartość zmienia się w usłudze, a składniki również zmieniają się, że wartość jest wyświetlana, rozwiązaniem jest BehaviourSubjects lub Replay Subject.
Saiyaff Farouk

1
Dziękuję Ci! ReplaySubjectz rozmiarem bufora 1 był dokładnie tym, czego potrzebowałem. Miałem strażnika trasy, który potrzebował wartości, ale musiał czekać na pierwszą emisję. Więc a BehaviorSubjectnie wycinałem tego, ponieważ nie chciałem wartości początkowej (też nullnie działałoby, ponieważ
używałem

1
@ menehune23 Potrzebowałem również ReplaySubject dla resolveklasy strażników Angular . Moja usługa danych może być asynchroniczna lub synchroniczna (jeśli dane zostały już pobrane). Jeśli był synchroniczny, obiekt Subject.next () był uruchamiany, zanim resolvefunkcja została zwrócona i została wewnętrznie zasubskrybowana przez Angular. BehaviourSubject prawdopodobnie zadziałałoby, ale musiałbym jawnie wywołać, complete()a także dodać nullsprawdzenia wartości początkowej. To, co zadziałało, było nowe ReplaySubject<DataType>(1) iresolveSubject.asObservable().take(1).map(....)
Drenai

1
Używam ReplaySubject z rozmiarem buforu 1, ale z jakiegoś powodu, gdy otrzymuję Observable z .asObservable()Observable, wysyłam wartość nulldo subskrybentów, zanim kiedykolwiek next()wywołam mój ReplaySubject. Myślałem, że nie powinno mieć wartości początkowej w przeciwieństwie do BehaviorSubject?
Kyle V.

2
Myślę, że całkiem prostym przykładem, o którym mógłbyś wspomnieć jako temat powtórki, byłby scenariusz „czatu” lub lobby gry, w którym chcesz, aby nowi uczestnicy widzieli 10 ostatnich wiadomości.
James

16

Poręczne podsumowanie różnych obserwowalnych typów, nieintuicyjne nazewnictwo, które znam lol .

  • Subject - Abonent otrzyma opublikowane wartości dopiero po dokonaniu subskrypcji.
  • BehaviorSubject - Nowi subskrybenci otrzymują ostatnią opublikowaną wartość LUB wartość początkową natychmiast po subskrypcji.
  • ReplaySubject - Nowi subskrybenci otrzymują wszystkie wcześniej opublikowane wartości natychmiast po subskrypcji

1-n opublikowanych wartości? Więc jeśli byłyby 2 opublikowane wartości, ReplaySubject dałoby -1 opublikowanych wartości ???
Jason Cheng

@JasonCheng no, po subskrypcji pobiera wszystkie wcześniej opublikowane wartości, zaktualizuj odpowiedź :)
Ricky Boyce

11
  1. Temat : Podczas subskrybowania zawsze pobiera dane, które są wysyłane po subskrypcji, tj. Poprzednie przekazane wartości nie są odbierane .
const mySubject = new Rx.Subject();

mySubject.next(1);

const subscription1 = mySubject.subscribe(x => {
  console.log('From subscription 1:', x);
});

mySubject.next(2);

const subscription2 = mySubject.subscribe(x => {
  console.log('From subscription 2:', x);
});

mySubject.next(3);

subscription1.unsubscribe();

mySubject.next(4);

W tym przykładzie, oto wynik, który zostanie wydrukowany w konsoli:

From subscription 1: 2
From subscription 1: 3
From subscription 2: 3
From subscription 2: 4

Zwróć uwagę, że subskrypcje, które przychodzą późno, nie obejmują niektórych danych, które zostały przesłane do tematu.

  1. Powtórz tematy : może pomóc, zachowując bufor poprzednich wartości, które zostaną wyemitowane do nowych subskrypcji.

Oto przykład użycia tematów powtórek, w których buffer of 2 previous valuessą przechowywane i emitowane przy nowych subskrypcjach:

const mySubject = new Rx.ReplaySubject(2);

mySubject.next(1);
mySubject.next(2);
mySubject.next(3);
mySubject.next(4);

mySubject.subscribe(x => {
  console.log('From 1st sub:', x);
});

mySubject.next(5);

mySubject.subscribe(x => {
  console.log('From 2nd sub:', x);
});

Oto, co daje nam to na konsoli:

From 1st sub: 3
From 1st sub: 4
From 1st sub: 5
From 2nd sub: 4
From 2nd sub: 5
  1. Tematy dotyczące zachowania : są podobne do tematów powtórek, ale ponownie wyemitują tylko ostatnią emitowaną wartość lub wartość domyślną, jeśli żadna wartość nie została wcześniej wyemitowana:
const mySubject = new Rx.BehaviorSubject('Hey now!');

mySubject.subscribe(x => {
  console.log('From 1st sub:', x);
});

mySubject.next(5);

mySubject.subscribe(x => {
  console.log('From 2nd sub:', x);
});

A wynik:

From 1st sub: Hey now!
From 1st sub: 5
From 2nd sub: 5

Źródła: https://alligator.io/rxjs/subjects/


4

Od: Randall Koutnik książka „Build Reactive Websites with RxJS”. :

Temat jest obiektem, który jest turbodoładowany obserwowalne. W swej istocie, Temat działa podobnie jak zwykły obserwowalne, ale każda subskrypcja jest podpięty do tego samego źródła. Podmioty są również obserwatorami i mają następne, błędne i wykonane metody, aby przesłać dane do wszystkich subskrybentów jednocześnie. Ponieważ podmioty są obserwatorami, mogą zostać przekazane bezpośrednio do wywołania subskrypcji, a wszystkie zdarzenia z pierwotnego obserwowalnego zostaną przesłane przez podmiot do jego subskrybentów.

Możemy użyć ReplaySubject do śledzenia historii. ReplaySubject rejestruje ostatnie wydarzenia N i Pałys je z powrotem do każdego nowego abonenta. Na przykład w aplikacji do czatu. Możemy go użyć do śledzenia historii poprzednich czatów.

BehaviorSubject jest uproszczona wersja ReplaySubject . Obiekt ReplaySubject przechowuje dowolną liczbę zdarzeń, a BehaviorSubject rejestruje tylko wartość ostatniego zdarzenia. Za każdym razem, gdy BehaviorSubject rejestruje nową subskrypcję, emituje najnowszą wartość do subskrybenta, a także wszelkie nowe wartości, które są przekazywane. The BehaviorSubject jest przydatny w przypadku pojedynczych jednostek stanu, takich jak opcje konfiguracji.


1

Najbardziej pozytywna odpowiedź jest po prostu błędna, twierdząc, że:

„Jeśli zainicjujesz a ReplaySubjectz rozmiarem bufora 1, to w rzeczywistości zachowuje się jak a BehaviorSubject


To nie jest do końca prawdą; sprawdź ten wspaniały wpis na blogu dotyczący różnic między nimi. Na przykład, jeśli zasubskrybujesz ukończone BehaviorSubject, nie otrzymasz ostatniej wartości, ale za a ReplaySubject(1)otrzymasz ostatnią wartość.

To jest ważna różnica, której nie należy przeoczyć:

const behavior = new BehaviorSubject(null);
const replay = new ReplaySubject(1);

behavior.skip(1).subscribe(v => console.log('BehaviorSubject:', v));
replay.subscribe(v => console.log('ReplaySubject:', v));

behavior.next(1);
behavior.next(2);
behavior.complete();
behavior.subscribe(v => console.log('Late B subscriber:', v));

replay.next(1);
replay.next(2);
replay.complete();
replay.subscribe(v => console.log('Late R subscriber:', v));

Sprawdź ten przykład kodu , który pochodzi z innego świetnego wpisu na blogu na ten temat.


0
     // ***********Subject  concept ***********
    let subject = new Subject<string>();


    subject.next("Eureka");
    subject.subscribe((data) => {
      console.log("Subscriber 1 got data >>>>> "+ data);
    });
    subject.subscribe((data) => {
      console.log("Subscriber 2 got data >>>>> "+ data);
    });

       // ********behaviour subject*********
    // Behavior subjects need a first value
let subject1 = new BehaviorSubject<string>("First value");


subject1.asObservable().subscribe((data) => {
  console.log("First subscriber got data behaviour subject>>>>> "+ data);
});
subject1.next("Second value")
  • Temat - subskrybent otrzyma opublikowane w nim wartości dopiero po dokonaniu subskrypcji.
  • BehaviorSubject - Nowi subskrybenci otrzymują ostatnią opublikowaną wartość LUB wartość początkową natychmiast po subskrypcji.
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.