Hot and Cold Observables: Are There 'Hot' and 'Cold' Operators

Hot and Cold observables: are there 'hot' and 'cold' operators?

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.

Simplified flow diagram

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.

Cold observable simplified flow diagram

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.

Hot observable simplified flow diagram

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 :

  • if there are no subscribers to 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 data
  • supposing that op1 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 :

  1. This information should be valid for Rxjs v4. While the version 5 has gone
    through considerable changes, most of it still applies verbatim.
  2. Unsubscription, error and completion flows are not represented, as
    they are not in the scope of the question. Schedulers are also not
    taken into account. Among other things, they influence the timing of
    the data flow, but a priori not its direction and content.
  3. According to the type of subject used for multicasting, there are
    different derived multicasting operators:


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?

Are all cold observables unicast and all hot observables multicast?

In the link provided by @lagoman (which I've read multiple times but still missed that point) I found some interesting explanation about hot-multicast relationship:

² Hot observables are usually multicast, but they could be listening to a producer that only supports one listener at a time. The grounds for calling it “multicast” at that point are a little fuzzy.

What are the Hot and Cold observables?

I hope this helps.

Can you give a comprehensive
definition for these terms?

See my blog post at: https://leecampbell.com/2010/08/19/rx-part-7-hot-and-cold-observables

Does it ever make sense to call
Publish on a hot observable or Defer
on a cold?

No, not that I can think of.

What are the aspects of Hot/Cold
conversions - do you lose messages,
for example?

It is possible to "lose" messages when the Observable is Hot, as "events" happen regardless of subscribers.

Are there differences between hot and
cold definitions for IObservable and
IEnumerable?

I dont really understand the question. I hope this analogy helps though. I would compare a Hot Observable to an Eagerly evaluated IEnumerable. ie a List or an Array are both Eagerly evaluated and have been populated even if no-one enuemerates over them. A yield statement that gets values from a file or a database could be lazily evaluated with the Yield keyword. While lazy can be good, it will by default, be reevaluated if a second enumerator runs over it. Comparing these to Observables, a Hot Observable might be an Event (Button click) or a feed of temperatures; these events will happen regardless of a subscription and would also be shared if multiple subscriptions were made to the same observale. Observable.Interval is a good example of a Cold observable. It will only start producing values when a subscription is made. If multiple subscriptions as made then the sequence will be re-evaluated and the "events" will occur at seperate times (depending on the time between subscriptions).

What are the general principles you should take into account when programming for cold or hot?

Refer to the link in point one. I would also recommend you look into Publsh being used in conjunction with RefCount. This allows you to have the ability to have Lazy evaluation semantics of Cold Observables but the sharing of events that Hot Observables get.

Any other tips on hot/cold
observables?

Get your hands dirty and have a play with them. Once you have read about them for more than 30minutes, then time spent coding with them is far more productive to you than reading any more :)

NgRx Selector - cold or hot observable

It's cold because it won't subscribe to the source until someone subscribes to it.

Most operators except for the share and publish operators create cold observables.

Hot vs Cold Observables

No. Documentation is the safest bet. Also, I disagree with @martin's comment, it absolutely does matter. You need to be careful with cold observables to avoid resubscribing and reissuing expensive operations (e.g. by using multicasting or saving off the result to a subject).

You also have to rely on the documentation to know when/how an observable completes. For example, you don't need to ever worry about unsubscribing from HttpClient.post because you know it will complete. However, if you're using some kind of wrapper around HttpClient which serves requests via a cached Subject you might not complete anymore. Every component will generate a new subscription and, after the component is destroyed, that subscription will be a reference from the Subject to the component so the component won't be garbage collected and you will end up with a memory leak.

There is no way to programmatically know what kind of Observable you've subscribed to, whether it will complete or not.

In general this is managed both by being smart about completing your observables and by using tools like takeUntil or Subscription to clean up subscriptions to long running non-completing observables or expensive observable workloads.

*EDIT: Actually, to clarify, you need to be careful with all observables, not just cold observables. Hot observables can generate expensive workloads too.

*EDIT2: Update example removing ActivatedRoute as those observables are completed when the component is destroyed.

Angular RxJS - fail to make cold observable hot

You could try shareReplay(1) to replay last value

https://www.learnrxjs.io/learn-rxjs/operators/multicasting/sharereplay

Also, a good article: https://itnext.io/the-magic-of-rxjs-sharing-operators-and-their-differences-3a03d699d255

What is the use case for cold observables?

The core of the answer lies in Ben Lesh's laconic summary:

TL;DR: You want a HOT observable when you don’t want to create your
producer over and over again.

In direct answer to the question "What's a case where you would prefer or use a cold observable over a hot one?", I'll offer both a general answer and a specific example.

Generally, it is far more convenient to use a cold observable to model streams that are created each time they are required than to create a hot one and try to wrangle it.

Specifically, consider the following trivial example. Say you want to respond to a click on a button by counting down from 10. If the button is clicked again during the countdown, it starts again at 10. If click$ models the button events, you might have something like this:

const subscription = click$
.flatMapLatest(_ => Rx.Observable.interval(1000).take(10))
.select(x => 10 - x)
.subscribe(x => console.log('clicked: ' + x));

Consider how this would be modelled without a cold observable. How would you:

  1. Initialize a stream in advance so that appropriate values were available when required?
  2. Avoid having to deal with the fraction of a second between the interval ticks and the time of your subscription?
  3. Deal with ordinals that can start at any number rather than just 1?
  4. Manage clean up logic for the stream?

1 and 3 can be addressed pretty easily, but 2 and 4 are nasty.

In answer to your second question "Is it laziness?" I would argue that it is not. A cold observable can leave it until the moment of subscription to produce its values. A hot observable can leave it until the moment of subscription to hook the appropriate events. They are both lazy in their own way (or at least, can be). The key difference lies in what Ben Lesh said: do you want to create a producer each time? And sometimes, you really do.



Related Topics



Leave a reply



Submit