Ich kann nicht herausfinden, wie publishReplay().refCount()
funktioniert.
Zum Beispiel ( Ссылка ):
%Vor%ergibt folgendes Ergebnis:
call observerA: 5
observerB: 5 call observerB: 5
observerC: 5 observerC: 5 call observerC: 5
BeobachterD: 5 BeobachterD: 5 BeobachterD: 5 Anruf BeobachterD: 5
1) Warum werden observerB, C und D mehrmals aufgerufen?
2) Warum wird "call" auf jeder Zeile und nicht am Anfang der Zeile gedruckt?
Auch wenn ich publishReplay(1).refCount()
aufrufe, ruft es die Observer B, C und D jeweils zweimal auf.
Was ich erwarte ist, dass jeder neue Beobachter den Wert 5 genau einmal erhält und "call" nur einmal gedruckt wird.
publishReplay(x).refCount()
kombiniert macht Folgendes:
ReplaySubject
, die bis zu x Emissionen wiedergibt. Wenn x nicht definiert ist, wird der gesamte Stream wiederholt. ReplaySubject
multicast-kompatibel mit einem refCount () -Operator. Dies führt dazu, dass gleichzeitige Abonnements die gleichen Emissionen erhalten. Ihr Beispiel enthält ein paar Probleme, die verdeutlichen, wie alles zusammen funktioniert. Siehe das folgende überarbeitete Snippet:
Beim Ausführen dieses Snippets können wir klar sehen, dass es keine doppelten Werte für Beobachter D ausgibt, es erzeugt tatsächlich neue Emissionen für jedes Abonnement. Wie kommt es?
Jedes Abonnement wird abbestellt, bevor das nächste Abonnement stattfindet. Dies führt dazu, dass refCount auf Null zurückgeht und kein Multicasting durchgeführt wird.
Das Problem liegt darin, dass der realSource
-Stream nicht abgeschlossen wird. Da es sich nicht um Multicasting handelt, erhält der nächste Abonnent eine neue Instanz von realSource
durch das ReplaySubject und die neuen Emissionen werden mit den zuvor bereits emittierten Emissionen vorangestellt.
Um zu verhindern, dass Ihr Stream die teure HTTP-Anfrage mehrmals aufruft, müssen Sie den Stream vervollständigen, damit das publishReplay weiß, dass es sich nicht erneut abonnieren muss.
Dies passiert, weil Sie publishReplay()
verwenden. Es erstellt intern eine Instanz von ReplaySubject
, die alle durchlaufenden Werte speichert.
Da Sie Observable.create
verwenden, wo Sie einen einzelnen Wert ausgeben, hängen Sie bei jedem Aufruf von source.subscribe(...)
einen Wert an den Puffer in ReplaySubject
an.
Sie erhalten call
nicht am Anfang jeder Zeile, weil es der ReplaySubject
ist, der seinen Puffer zuerst ausgibt, wenn Sie ihn abonnieren und dann seine Quelle selbst abonniert:
Details zur Implementierung finden Sie unter:
Gleiches gilt für die Verwendung von publishReplay(1)
. Zuerst gibt es den gepufferten Gegenstand von ReplaySubject
und dann noch einen Gegenstand von observer.next(5);
Im Allgemeinen: refCount
bedeutet, dass der Stream heiß / geteilt ist, solange mindestens ein Teilnehmer vorhanden ist - er wird jedoch zurückgesetzt / kalt, wenn keine Teilnehmer vorhanden sind.
Dies bedeutet, wenn Sie absolut sicher sein wollen, dass nichts mehr als einmal ausgeführt wird, sollten Sie nicht refCount()
, sondern einfach connect
den Stream verwenden, um es heiß zu setzen.
Als zusätzliche Anmerkung: Wenn Sie observer.complete()
nach observer.next(5);
hinzufügen, erhalten Sie auch das erwartete Ergebnis.
Hinweis: Müssen Sie wirklich Ihre eigene benutzerdefinierte Obervable
hier erstellen? In 95% der Fälle reichen die vorhandenen Betreiber für den gegebenen Anwendungsfall aus.