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 understand the difference between a Subject and an Observable, you need to be aware of two distinct concepts
– A data producer
– A data consumer

An observable, by definition is a data producer. Albeit a special kind that can produce data over time.

A Subject on the other hand can act as both – a data producer and a data consumer.

This implies two things.
1. A subject can be subscribed to, just like an observable.
2. A subject can subscribe to other observables.

That being said, there is one critical difference between a subject and an observable.

All subscribers to a subject share the same execution of the subject. i.e. when a subject produces data, all of its subscribers will receive the same data. This behavior is different from observables, where each subscription causes an independent execution 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
observable.subscribe(subject);

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

There are a few important things to notice about this example.
1. I had to setup my subscriptions before my subject subscribed to the source.
2. Both the consumers logged the same value for v.

The fact that our consumers log the same data implies that the broadcasted data is shared with all the consumers/subscribers. This is unlike observables, where each consumer/subscriber causes the observable function to be re-executed.

Lets see another example to clarify this.

Example 1

Vanilla observable, independent 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

Example 2

Observable wrapped in a subject, causing 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 manually broadcast data from a subject to it observers using the next() function 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 effectively takes you a step closer towards getting comfortable with using Subjects and Observables in your projects with confidence.

Ryan Sukale

Ryan is just a regular guy next door trying to manage his life and finances.

You may also like...

  • Gerard Martínez

    Is a good tutorial, but there’s some errors, maybe they are intentional? For example:

    source.subscribe(observable);

    should be

    observable.subscribe(subject);

    Thanks!

    • tutorialhorizon

      Thanks for pointing it out! I have fixed it now.

    • MoonRise

      Of course there are mistakes – this is an rxjs tutorial

  • Envil

    Very good explanation! Thank you!

  • Charles Robertson

    I have to say this is the best tutorial I have read so far on observables. I still can’t really get my head around this topic, though, coming from a vanilla JS background. It just seems so counter intuitive.

    • tutorialhorizon

      I understand. RX takes time to wrap your head around. But the ability to compose things make its absolutely beautiful. Its makes you feel like you’re making lego blocks to ultimately build castles.

      Thanks for all the questions. I try to reply to comments whenever I get time, which is more likely over the weekends. Feel free to ask more questions as you continue learning and I will try my best to explain what I know.

      • Charles Robertson

        Thanks for taking the time to reply. I am using Angular 4’s inbuilt ‘http’ observable as a starting point to try & understand the concept properly.

        So far, I know this:

        1. The ‘http’ observable requests data from the server

        2. The subscriber then passes a callback into subscribe() that uses the ‘http’ response, when it arrives back to the client

        So, internally, the observable’s observer ‘next’ method pushes the ‘http’ response towards its subscribers. The subscriber’s callback can then access & process the response.

        Does this sound OK?

        • tutorialhorizon

          See my reply to your other comment.

          • Charles Robertson

            Thanks. I have checked out your links. Excellent series of tutorials. Very clear & concise.

  • tutorialhorizon

    Hi Charles,

    the consumer is an object with three methods – {next, error, complete}. These three methods internally manage the invocation of the subscriber and do all the bookkeeping so you don’t have to. Therefore, within the subscribe method, when you invoke consumer.next(data), youre just pushing data to the subscriber.

    • Charles Robertson

      So, using Angular’s in-built ‘http’ observable, as an example. When the observable is subscribed to:

      observable.subscribe(subject)

      The subject here could be a callback function.

      The callback function is passed into the observable, where it is stored, until the ‘http’ observable itself receives a response back from the server. Just before the observable’s internal observer’s ‘next’ method fires, the stored callback is provided with the server response data. The result of the executed callback is now pushed, using the observable’s internal observer’s ‘next’ method to its subscriber, which, is, in fact, the observable itself.

      How am I doing?

      • tutorialhorizon

        I am not familiar with angular, but I would expect common rjxs patterns to be the same across all implementation.

        I am noticing that throughout your comments, you haven’t mentioned the concept of streams. That might be the missing piece of your puzzle.

        Here’s my little explanation
        – A stream is something that emits data at various points of time. When you create an observable via observable.create, you are describing a stream and what data it emits.
        – The way you emit data on a stream is by calling next() from within the observable.create callback argument. Which in my examples, was just emitting random numbers on the stream.
        – The callback function that you provide to the subscribe() method is the subscriber. This subscriber will receive data whenever something is emitted on the stream.

        If you check our website category for Rxjs – https://javascript.tutorialhorizon.com/tag/rxjs-2/, I have written some articles to help describe streams as well. This is the first among those articles – in which i talk about streams https://javascript.tutorialhorizon.com/2017/04/28/rxjs-tutorial-getting-started-with-rxjs-and-streams/

        See if it helps.

        • Charles Robertson

          Thanks. I will certainly look at the links you have provided. I think the difficulty I am having here, is due to the different terminology used within the RxJs community. Some people use producer -> consumer, others use observable -> subject, and others use observable -> observer etc. What would be really useful, is a diagram that shows how the lifecycle of an observable works, with all the possible naming conventions highlighted. I will keep persevering with this subject, because I can see the benefits of a “push” approach.

          • tutorialhorizon

            I see. Well, I guess every writer prefers to follow a naming pattern. I just picked what made sense to me in order to explain. Its a bit rough when starting out, but once you understand that basically there are just streams, data emitters(which put data on a stream) and data consumers(which read the data from a stream), you will be able to understand things irrespective of what blog posts you come across.

          • Charles Robertson

            Thanks Ryan. One last question. Sometimes I see in example Angular 4 code, something like:

            public foo: subscription;

            So, there seem to be 3 actors:

            observable
            subject
            subscription

            Now, I have got a handle on the first 2, but what does the 3rd do?

            Is it a way of assigning what is returned from an observable?

            So rather than:

            observable.subscribe(subject)

            A subscription pattern is:

            subscription = observable.subscribe(subject)

            And then later on:

            subscription.subscribe(subject)

            So, is it a way of holding a reference to an observable?

          • tutorialhorizon

            `subscription` in this case would just be an object which you could later use to cancel. Its analogous to the way setInterval returns an intervalId which can later be used to cancel the interval. Just in this case, the subscription is an object. And perhaps supports chaining in your example.

  • tutorialhorizon

    Hi Charles,

    You’re right. Observables push data. Let me try to explain what push and pull means.

    When you write code “var value = Math.random()”, it is considered a PULL, because you are explicitly invoking a function and asking it to return data to you right away.
    Whereas when you write code like source.next(Math.random()), its a PUSH because you have no idea who the subscriber is, in fact you don’t even know if there is a subscriber who will consume the data.