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

Difference between Rxjs Subject and Observable

In order to under­stand the dif­fer­ence between a Sub­ject and an Observ­able, you need to be aware of two dis­tinct con­cepts
– A data pro­ducer
– A data consumer

An observ­able, by def­i­n­i­tion is a data pro­ducer. Albeit a spe­cial kind that can pro­duce data over time.

A Sub­ject on the other hand can act as both — a data pro­ducer and a data consumer.

This implies two things.
1. A sub­ject can be sub­scribed to, just like an observ­able.
2. A sub­ject can sub­scribe to other observables.

That being said, there is one crit­i­cal dif­fer­ence between a sub­ject and an observable.

All sub­scribers to a sub­ject share the same exe­cu­tion of the sub­ject. i.e. when a sub­ject pro­duces data, all of its sub­scribers will receive the same data. This behav­ior is dif­fer­ent from observ­ables, where each sub­scrip­tion causes an inde­pen­dent exe­cu­tion of the observable.

Lets see some examples

var subject = new Rx.Subject();

// Here the subject is acting like a data producer
// because it is being subscribed to
subject.subscribe(v => console.log('consumer A: ' + v));
subject.subscribe(v => console.log('consumer B: ' + v));

// Create a source of the data, which in our case is an observable
var observable = Rx.Observable.from([0, 1]);

// Here the same subject acs as a data consumer because it
// can subscribe to another observable
source.subscribe(observable);

/* Prints */
// Consumer A: 0
// Consumer B: 0
// Consumer A: 1
// Consumer B: 1

There are a few impor­tant things to notice about this exam­ple.
1. I had to setup my sub­scrip­tions before my sub­ject sub­scribed to the source.
2. Both the con­sumers logged the same value for v.

The fact that our con­sumers log the same data implies that the broad­casted data is shared with all the consumers/subscribers. This is unlike observ­ables, where each consumer/subscriber causes the observ­able func­tion to be re-executed.

Lets see another exam­ple to clar­ify this.

Exam­ple 1

Vanilla observ­able, inde­pen­dent execution

var observable = Rx.Observable.create(function(source) {
  source.next(Math.random());
});

observable.subscribe(v => console.log('consumer A: ' + v));
observable.subscribe(v => console.log('consumer B: ' + v));

/* Prints DIFFERENT values for both consumers */
// consumer A: 0.25707833297857885
// consumer B: 0.8304769607422662

Exam­ple 2

Observ­able wrapped in a sub­ject, caus­ing shared execution

var observable = Rx.Observable.create(function(source) {
  source.next(Math.random());
});

var subject = new Rx.Subject();

subject.subscribe(v => console.log('consumer A: ' + v));
subject.subscribe(v => console.log('consumer B: ' + v));

observable.subscribe(subject);

/* Prints SAME values for both consumers */
// consumer A: 0.8495447073368834
// consumer B: 0.8495447073368834

You can also man­u­ally broad­cast data from a sub­ject to it observers using the next() func­tion as shown below.

var subject = new Rx.Subject();

subject.subscribe(v => console.log('consumer A: ' + v));

subject.next('hello world');

/* Prints */
// consumer A: hello world

I hope this post effec­tively takes you a step closer towards get­ting com­fort­able with using Sub­jects and Observ­ables in your projects with confidence.

Ryan Sukale

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

You may also like...