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("
");
};}
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 :
- 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 :
- This information should be valid for Rxjs v4. While the version 5 has gone
through considerable changes, most of it still applies verbatim.
- 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.
- 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?