I reviewed the following SO question: What are the Hot and Cold observables?
To summarize:
Yet, I feel like hot vs. cold is still a source of confusion. So here are my questions:
Are all rx observables cold by default (with the exception of subjects)?
I often read that events are the typical metaphor for hot observables, but I also read that Rx.fromEvent(input, 'click')
is a cold observable(?).
Are there/what are the Rx operators which turn a cold observables into a hot observable (apart from publish
, and share
)?
For instance, how does it work with Rx operator withLatestFrom
? Let cold$
be a cold observable which has somewhere been subscribed to. Will sth$.withLatestFrom(cold$,...)
be a hot observable?
Or if I do sth1$.withLatestFrom(cold$,...), sth2$.withLatestFrom(cold$,...)
and subscribe to sth1
and sth2
, will I always see the same value for both sth
?
I thought Rx.fromEvent
creates cold observables but that is not the case, as mentioned in one of the answers. However, I am still baffled by this behaviour: https://codepen.io/anon/pen/NqQMJR?editors=101. Different subscriptions get different values from the same observable. Wasn't the click
event shared?
An Observable is cold when data is produced inside the Observable and the Observable is hot when the data is produced outside the Observable.
fromEvent(input, 'click') is a cold observable(?).
Creation Operators This operator will create an observable from an array, an array-like object, a promise, an iterable object, or an observable-like object. This operator will give output as an observable that is to be used on elements that emit an event for example buttons, clicks, etc.
ConcatAll This operator combines all emitted inner streams and just as with plain concat sequentially produces values from each stream.
There are two types of observables: hot and cold. The main difference is that a cold observable creates a data producer for each subscriber, whereas a hot observable creates a data producer first, and each subscriber gets the data from one producer, starting from the moment of subscription.
It makes a hot observable or observable-returning function cold. Operators such as Merge and Concat, among many other combining/zipping/joining operators, can add subscription side effects to hot observables by combining them with cold observables, thus returning cold observables.
Observables can be classified into two main groups: hot and cold Observables. Let's start with a cold Observable. Copied! In the above case subscriber B subscribes 2000ms after subscriber A.
In the simplest case, an observable may be permanently hot or permanently cold , though some observables change their temperature over time so that different observers may get different temperatures; therefore: The temperature of an observable is relative to the time of subscription.
I am coming back a few months later to my original question and wanted to share the gained knowledge in the meanwhile. I will use the following code as an explanation support (jsfiddle):
var ta_count = document.getElementById('ta_count'); var ta_result = document.getElementById('ta_result'); var threshold = 3; function emits ( who, who_ ) {return function ( x ) { who.innerHTML = [who.innerHTML, who_ + " emits " + JSON.stringify(x)].join("\n"); };} var messages$ = Rx.Observable.create(function (observer){ var count= 0; setInterval(function(){ observer.onNext(++count); }, 1000) }) .do(emits(ta_count, 'count')) .map(function(count){return count < threshold}) .do(emits(ta_result, 'result')) messages$.subscribe(function(){});
As mentioned in one of the answers, defining an observable leads to a series of callback and parameter registration. The data flow has to be kicked in, and that is done via the subscribe
function. A (simplified for illustration) detailed flow can be find thereafter.
Observables are cold by default. Subscribing to an observable will result in an upstream chain of subscriptions taking place. The last subscription leads to the execution of a function which will handle a source and emit its data to its observer.
That observer in its turn emits to the next observer, resulting in a downstream flow of data, down to the sink observer. The following simplified illustration shows subscription and data flows when two subscribers subscribe to the same observable.
Hot observables can be created either by using a subject, or through the multicast
operator (and its derivatives, see Note 3 below).
The multicast
operator under the hood makes use of a subject and returns a connectable observable. All subscriptions to the operator will be subscriptions to the inner subject. When connect
is called, the inner subject subscribes to the upstream observable, and data flows downstream. Subjects manipulate internally a list of subscribed observers and multicast incoming data to all subscribed observers.
The following diagram summarizes the situation.
In the end, it matters more to understand the flow of data caused by the observer pattern and the implementation of the operators.
For instance, if obs
is hot, is hotOrCold = obs.op1
cold or hot? Whatever the answer is :
obs.op1
, no data will flow through op1
. If there were subscribers to hot obs
, that means obs.op1
will have possibly lost pieces of dataop1
is not a multicast-like operator, subscribing twice to hotOrCold
will subscribe twice to op1
, and every value from obs
will flow twice through op1
.Notes :
Subject type | `Publish` Operator | `Share` operator ------------------ | --------------------------- | ----------------- Rx.Subject | Rx.Observable.publish | share Rx.BehaviorSubject | Rx.Observable.publishValue | shareValue Rx.AsyncSubject | Rx.Observable.publishLast | N/A Rx.ReplaySubject | Rx.Observable.replay | shareReplay
Update : See also the following articles, here, and there) on that subject by Ben Lesh.
Further details on subjects can be found in this other SO question : What are the semantics of different RxJS subjects?
Your summary, and the linked question are both correct, I think the terminology may be confusing you. I propose you think of hot and cold observables as active and passive observables (respectively).
That is, an active (hot) observable will be emitting items whether someone has subscribed or not. The canonical example, again, button click events happen whether someone is listening to them or not. This distinction is important because, if, for example, I click a button and then subscribe to button clicks (in that order), I will not see the button click that has already happened.
A passive (cold) observable will wait until a subscriber exists before emitting items. Imagine a button where you cannot click on it until someone is listening to the events—this would ensure that you always see each and every click event.
Are all Rx observables "cold" (or passive) by default? No, Rx.fromEvent(input, 'click')
for example is a hot (or active) observable.
I also read that
Rx.fromEvent(input, 'click')
is a cold observable(?)
That is not the case.
Are there Rx operators which turn a cold observable into a hot observable?
The concept of turning a hot (active) observable into a cold (passive) observable is this: you need to record the events that happen while nothing is subscribed and offer those items (in various ways) to subscribers that come along in the future. One way to do this is to use a Subject. For example, you could use a ReplaySubject
to buffer up items emitted and replay them to future subscribers.
The two operators you named (publish
and share
) both use subjects internally to offer that functionality.
How does it work with Rx operator
withLatestFrom
? Letcold$
be a cold observable which has been subscribed to. Willsomething$.withLatestFrom(cold$,...)
be a hot observable?
If something
is a hot observable, then yes. If something
is a cold observable, then no. Going back to the events example, if something
is a stream of button click events:
var clickWith3 = Rx.fromEvent(input, 'click') .withLatest(Rx.Observable.from([1, 2, 3]);
Or if I do
foo$.withLatestFrom(cold$,...), bar$.withLatestFrom(cold$,...)
and subscribe tofoo
andbar
, will I always see the same values for both?
Not always. Again, if foo
and bar
are clicks on different buttons for example, then you would see different values. As well, even if they were the same button, if your combination function (the 2nd argument to withLatest
) does not return the same result for the same inputs, then you would not see the same values (because it would be called twice, as explained below).
I thought
Rx.fromEvent
creates cold observables but that is not the case, as mentioned in one of the answers. However, I am still baffled by this behaviour: codepen.io/anon/pen/NqQMJR?editors=101. Different subscriptions get different values from the same observable. Wasn't theclick
event shared?
I'll point you to this great answer by Enigmativity to a question I had about the same behaviour. That answer will explain it a lot better than I can, but the gist of it is that the source (the click event) is "shared", yes, but your operations on it are not. If you want to share not just the click event but also the operation on it, you will need to do so explicitly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With