Show Buttons
Share On Facebook
Share On Twitter
Share On Google Plus
Share On Linkdin
Share On Reddit
Share On Stumbleupon
Contact us
Hide Buttons

Understanding the Rx multicast operator

By default, observ­ables are uni­cast. i.e. each sub­scriber causes the observ­able to be invoked inde­pen­dently. In con­trast, a mul­ti­cas­ted observ­able is one that emits the same data to all the subscribers.

This is achieved by call­ing the multicast(subject) func­tion on the observ­able instance and pass­ing it a sub­ject. For e.g.

var multicast = Rx.Observable
                .interval(500)
                .take(4)
                .multicast(new Rx.Subject());

Think of the sub­ject as a mid­dle­man in a mul­ti­cast observ­able. It merely relays data from the under­ly­ing observ­able and shares it among all the subscribers.

A mul­ti­cas­ted observ­able also dif­fers in terms of when it can begin exe­cu­tion. You con­trol it by call­ing the connect() func­tion on the observ­able instance.

A mul­ti­cast observ­able is also known as a con­nectable observ­able. aka. Data is emit­ted only after you invoke the connect() func­tion on the mul­ti­cas­ted instance. This is because the sub­ject only sub­scribes to the under­ly­ing observ­able when con­nect() is invoked.

var multicast = Rx.Observable
                .interval(500)
                .take(4)
                .multicast(new Rx.Subject());

// Nothing happens on subscription
multicast.subscribe(d => console.log('Data + ' + d));

// This triggers the underlying subscription
// and data begins to arrive on the subscriber
multicast.connect();

Mul­ti­cast with late subscribers

The mul­ti­cast oper­a­tion is spe­cial because the under­ly­ing observ­able exe­cutes just once, and not on a per sub­scrip­tion basis. How­ever this has an impor­tant impli­ca­tion. If the under­ly­ing observer com­pletes, the mid­dle­man sub­ject also com­pletes. So any sub­scribers that get added in the future will not receive any data.

In gen­eral, once a sub­ject com­pletes, future sub­scribers to a sub­ject will not receive more data.

(There are other kinds of sub­jects that offer a slight vari­a­tion, but we will cover that in another arti­cle.)

Lets see an exam­ple to demon­strate the com­ple­tion behav­iour of a mul­ti­cas­ted observ­able. Make sure to read the inline comments.

// Create a regular observable
var observable = Rx.Observable.interval(500).take(4);

// Create a subject that we use as a way to mulitcast
var sub = new Rx.Subject();

// Multicast it
var source = observable.multicast(sub);

// Subscriber 1: Add a subscriber before the observer starts emitting
source.subscribe(x => console.log('A : ' + x));

// This is when the subject actually connects to the source
// and data can begin to emit
source.connect();

// Subscriber 2: Add a subscriber while the observer is still emitting,
setTimeout(() => {
  source.subscribe(x => console.log('B : ' + x));
}, 1200);

// Subscriber 3: Add a subscriber long after the observable is done emitting
setTimeout(() => {
  source.subscribe(x => console.log('C : ' + x));
}, 2400);

// Output
/*
A : 0
A : 1
A : 2
B : 2
A : 3
B : 3
*/

As you notice in the out­put, sub­scriber A received all the data points. Sub­scriber B, since it joins some­time dur­ing half­time, just receives the last 2 data points. After that, the source com­pletes, therby com­plet­ing the mid­dle­man sub­ject as well. Even­tu­ally when sub­scriber C joins really late, every­thing is already com­pleted so it never receives any data.

Some­times I like to think of a mul­ti­cas­ted observ­able as a live foot­ball match. You can only enjoy the game with every­one as long as you join the view­ing party while it is being broad­casted live. Once it is over, there is no point join­ing because, well, it is over.

I will cover another vari­a­tion of the mul­ti­cas­ted observ­able in another arti­cle. But I hope you find this arti­cle useful.

Ryan Sukale

Ryan is a UX engineer living in San Francisco, California.

You may also like...