2016-06-22 4 views
2

Ich erstelle diesen Stift: http://codepen.io/hatelove85911/pen/VjmwwbWann gibt der heiß beobachtbare erste Wert aus?

const Ob = Rx.Observable 
const button = document.querySelector('#click') 

const count$ = Ob.fromEvent(button, 'click') 
       .scan(acc=>++acc,0) 
       .share() 
setTimeout(()=>{ 
    count$.subscribe(x=>console.log('sub1:',x)) 
},5000) 

setTimeout(()=>{ 
    count$.subscribe(x=>console.log('sub2:',x)) 
},10000) 

alle Online-Beiträge sagen, dass heiße beobachtbaren beginnt Werte sogar emittieren, wenn kein Teilnehmer ist.

In diesem Beispiel habe ich das Observable geteilt, um es heiß zu machen. Ich klicke mehrmals auf die Schaltfläche und erwarte einen kumulierten Wert größer als 1 vor dem ersten Abonnenten, aber wenn der erste Abonnent kommt, beginnt sein Protokoll noch bei 1, jedoch beginnt das Protokoll des zweiten Abonnenten in der Mitte , nicht von 1.

Kann jemand erklären, warum das passiert?

+0

Ich bin nicht sehr vertraut mit RXJS, aber wo geben Sie an, dass eine heiße und nicht kalt beobachtbar ist? – paul

+0

Ich denke, standardmäßig sollte Button klicken heiß sein, oder? Denn unabhängig davon, ob es sich um einen Abonnenten handelt, wird der Button immer noch angeklickt. Ich habe die Methode '.share()' verwendet, um sicherzustellen, dass es heiß ist. –

Antwort

3

Die heiß/warm/kalt Terminologie wird immer verwirrend sein. Ich versuche der Temperaturmetapher zu entkommen, um genau zu verstehen, was unter der Haube passiert.

Also im Grunde sind alle (Rxjs) Observablen (mit Ausnahme der Themen) faul. Das heißt, wenn es keine Abonnenten (auch Beobachter genannt) gibt, wird kein Datenfluss (oder irgendetwas in der Tat) stattfinden. Sie finden eine illustrierte und genauere Erklärung der Subskription und der Datenflüsse, die sich hier im Abonnement abspielen: Hot and Cold observables : are there 'hot' and 'cold' operators?

share gibt ein Observable zurück, so dass Observable auch faul ist. Der Produzent (der von der Verkettung des Betreibers spezifiziert wird) startet somit zum ersten Mal mit dem ersten Abonnement. Also egal, auf was Sie vor dem Abonnement klicken, nichts wird ausgeführt. Wenn Sie einmal abonniert haben, wird Ihr Producer ausgeführt und Ihr Beobachter/Abonnement generiert den Wert 1.

Wie Sie in der verknüpften dargestellten Datenfluß sehen können, share ist ein Alias ​​für publish().refCount(), wo publish ist multicast(new Rx.Subject()) so Ob.fromEvent(button, 'click').scan(acc=>++acc,0) ein Thema abonniert hat. Der wichtige Punkt hier ist, dass das Thema tatsächlich noch nicht abonniert hat, aber wenn Sie connect() anrufen werden. Sobald das Subjekt abonniert hat, wird es alle Werte, die es erhält, an alle Beobachter, die es bei ihm registriert hat, weiterleiten in dem Moment, in dem der Wert ankommt. Dieses Verhalten wird als heißes Verhalten angesehen. Der verwirrende Teil ist, dass heiße Observable Observable sind und daher immer noch faul sind (mit Ausnahme von Fächern, die nicht faul sind).

Im Detail geht publish eine verbindbare Observable zurück (immer noch faul). Wenn Sie es abonnieren, abonnieren Sie das oben genannte Thema. Aber solange Sie nicht connect() tun, ist das Subjekt selbst nicht an der Quelle beobachtbar. Daher werden keine Daten fließen.

Um Sie davon zu überzeugen, ersetzen Sie Ihre codepen mit:

const Ob = Rx.Observable 
const button = document.querySelector('#click') 

const count$ = Ob.fromEvent(button, 'click') 
       .scan(acc=>++acc,0) 
       .publish(); 
setTimeout(()=>{ 
    count$.subscribe(x=>console.log('sub1:',x)) 
},1000) 


setTimeout(()=>{ 
    count$.subscribe(x=>console.log('sub2:',x)) 
    count$.connect(); 
},5000) 

kurz So in obs.publish(); obs.subscribe(observer1), haben Sie Verbindung, bevor der Zustand nach obs | subject -> observer1 wo a-->bb is subscribed to a bedeutet. Es werden keine Daten fließen, da das Subjekt nur Werte weitergibt, die es empfängt, und es empfängt keine, da es keine Quelle abonniert hat. Wenn Sie connect() haben, haben Sie den Status: obs -> subject -> observer1. Daher wird obs Producer starten, Wert an das Subjekt senden, das wiederum Werte an jeden Beobachter sendet, den es zum Zeitpunkt des Empfangs dieser Werte hat.

+0

Vielen Dank für Ihre Antwort. Jetzt weiß ich alles zu verstehen, ich muss die Implementierung dahinter verstehen. Heiß und kalt sind wirklich verwirrend, oder es ist verwirrend, weil kein gutes Material den Datenfluss erklärt, Abonnement im Detail. –

+0

Kann ich diese bestätigen: 1. heiß beobachtbare Mittel unter der Haube, verwenden sie alle Subjekt als Vermittler zu Multicast-Werte von der Quelle zu den Teilnehmern. 2. Ob heiß oder kalt beobachtbar, sie geben nur Werte aus, wenn mindestens ein Teilnehmer vorhanden ist. 3. Viele Online-Posts sind falsch, sie sagen heiß Observable wird Werte unabhängig davon, ob es Abonnenten oder nicht emittiert, heiß beobachtbare wird nur Werte emittieren, wenn es mindestens einen Abonnenten gibt. –

+0

Nun, wenn beobachtbar wir die Javascript-Objekte in Rxjs definiert, dann ja zu 1. Ein Vorbehalt für 2 - Themen wird emittieren, auch wenn es keinen Abonnenten gibt (dh sie sind nicht faul) und Sie müssen immer erwähnen, weil sie sind Observable auch (sowie Beobachter). Was passiert, ist manchmal heiß zu beobachten, wenn man sich nicht auf das JavaScript-Objekt bezieht, sondern auf die Quelle selbst (zum Beispiel die Reihenfolge der Klicks gegenüber dem JavaScript-Objekt, das diese Sequenz darstellt): Das Objekt ist faul und beobachtbar während die Reihenfolge der Klicks ist passiert, ob Sie zuhören oder nicht). – user3743222

1

Ich bin neu zu RxJS auch, aber ich glaube, die fromEvent ist eher wie eine "warme" Observable. Grundsätzlich ist es faul, dass es nicht beginnt, Dinge zu verfolgen, bis ein tatsächliches Abonnement darauf passiert. share macht es heiß, sobald ein Abonnement passiert ist, aber bis zum ersten Abonnement wegen seiner Faulheit nichts verfolgt wird, so ist es immer noch eher ein "warmes" Observable in diesem Sinne.

Um es wirklich heiß zu machen/nicht faul, dass, werden Klicks vor dem ersten Abonnement verfolgt Sie .publish() (die gibt einen ConnectableObservables) und dann sofort .connect() es verwenden können.

Codepen.io Example

const Ob = Rx.Observable 
const button = document.querySelector('#click') 

const count$ = Ob.fromEvent(button, 'click') 
       .scan(acc=>++acc,0) 
       .publish(); // <-- publish here 

count$.connect(); // <--immediately connect to it 

setTimeout(()=>{ 
    count$.subscribe(x=>console.log('sub1:',x)) 
},5000) 


setTimeout(()=>{ 
    count$.subscribe(x=>console.log('sub2:',x)) 
},10000) 
Verwandte Themen