BehaviorSubject vs Observable?

529,078

Solution 1

BehaviorSubject is a type of subject, a subject is a special type of observable so you can subscribe to messages like any other observable. The unique features of BehaviorSubject are:

  • It needs an initial value as it must always return a value on subscription even if it hasn't received a next()
  • Upon subscription, it returns the last value of the subject. A regular observable only triggers when it receives an onnext
  • at any point, you can retrieve the last value of the subject in a non-observable code using the getValue() method.

Unique features of a subject compared to an observable are:

  • It is an observer in addition to being an observable so you can also send values to a subject in addition to subscribing to it.

In addition, you can get an observable from behavior subject using the asObservable() method on BehaviorSubject.

Observable is a Generic, and BehaviorSubject is technically a sub-type of Observable because BehaviorSubject is an observable with specific qualities.

Example with BehaviorSubject:

// Behavior Subject

// a is an initial value. if there is a subscription 
// after this, it would get "a" value immediately
let bSubject = new BehaviorSubject("a"); 

bSubject.next("b");

bSubject.subscribe(value => {
  console.log("Subscription got", value); // Subscription got b, 
                                          // ^ This would not happen 
                                          // for a generic observable 
                                          // or generic subject by default
});

bSubject.next("c"); // Subscription got c
bSubject.next("d"); // Subscription got d

Example 2 with regular subject:

// Regular Subject

let subject = new Subject(); 

subject.next("b");

subject.subscribe(value => {
  console.log("Subscription got", value); // Subscription wont get 
                                          // anything at this point
});

subject.next("c"); // Subscription got c
subject.next("d"); // Subscription got d

An observable can be created from both Subject and BehaviorSubject using subject.asObservable().

The only difference being you can't send values to an observable using next() method.

In Angular services, I would use BehaviorSubject for a data service as an angular service often initializes before component and behavior subject ensures that the component consuming the service receives the last updated data even if there are no new updates since the component's subscription to this data.

Solution 2

Observable: Different result for each Observer

One very very important difference. Since Observable is just a function, it does not have any state, so for every new Observer, it executes the observable create code again and again. This results in:

The code is run for each observer . If its a HTTP call, it gets called for each observer

This causes major bugs and inefficiencies

BehaviorSubject (or Subject ) stores observer details, runs the code only once and gives the result to all observers .

Ex:

JSBin: http://jsbin.com/qowulet/edit?js,console

// --- Observable ---
let randomNumGenerator1 = Rx.Observable.create(observer => {
   observer.next(Math.random());
});

let observer1 = randomNumGenerator1
      .subscribe(num => console.log('observer 1: '+ num));

let observer2 = randomNumGenerator1
      .subscribe(num => console.log('observer 2: '+ num));


// ------ BehaviorSubject/ Subject

let randomNumGenerator2 = new Rx.BehaviorSubject(0);
randomNumGenerator2.next(Math.random());

let observer1Subject = randomNumGenerator2
      .subscribe(num=> console.log('observer subject 1: '+ num));
      
let observer2Subject = randomNumGenerator2
      .subscribe(num=> console.log('observer subject 2: '+ num));
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.3/Rx.min.js"></script>

Output :

"observer 1: 0.7184075243594013"
"observer 2: 0.41271850211336103"
"observer subject 1: 0.8034263165479893"
"observer subject 2: 0.8034263165479893"

Observe how using Observable.create created different output for each observer, but BehaviorSubject gave the same output for all observers. This is important.


Other differences summarized.

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃         Observable                  ┃     BehaviorSubject/Subject         ┃      
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ 
┃ Is just a function, no state        ┃ Has state. Stores data in memory    ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ Code run for each observer          ┃ Same code run                       ┃
┃                                     ┃ only once for all observers         ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ Creates only Observable             ┃Can create and also listen Observable┃
┃ ( data producer alone )             ┃ ( data producer and consumer )      ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ Usage: Simple Observable with only  ┃ Usage:                              ┃
┃ one Obeserver.                      ┃ * Store data and modify frequently  ┃
┃                                     ┃ * Multiple observers listen to data ┃
┃                                     ┃ * Proxy between Observable  and     ┃
┃                                     ┃   Observer                          ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

Solution 3

Observable and subject both are observable's means an observer can track them. but both of them have some unique characteristics. Further there are total 3 type of subjects each of them again have unique characteristics. lets try to to understand each of them.

you can find the practical example here on stackblitz. (You need to check the console to see the actual output)

enter image description here

Observables

They are cold: Code gets executed when they have at least a single observer.

Creates copy of data: Observable creates copy of data for each observer.

Uni-directional: Observer can not assign value to observable(origin/master).

Subject

They are hot: code gets executed and value gets broadcast even if there is no observer.

Shares data: Same data get shared between all observers.

bi-directional: Observer can assign value to observable(origin/master).

If are using using subject then you miss all the values that are broadcast before creation of observer. So here comes Replay Subject

ReplaySubject

They are hot: code gets executed and value get broadcast even if there is no observer.

Shares data: Same data get shared between all observers.

bi-directional: Observer can assign value to observable(origin/master). plus

Replay the message stream: No matter when you subscribe the replay subject you will receive all the broadcasted messages.

In subject and replay subject you can not set the initial value to observable. So here comes Behavioral Subject

BehaviorSubject

They are hot: code gets executed and value get broadcast even if there is no observer.

Shares data: Same data get shared between all observers.

bi-directional: Observer can assign value to observable(origin/master). plus

Replay the message stream: No matter when you subscribe the replay subject you will receive all the broadcasted messages.

You can set initial value: You can initialize the observable with default value.

Solution 4

The Observable object represents a push based collection.

The Observer and Observable interfaces provide a generalized mechanism for push-based notification, also known as the observer design pattern. The Observable object represents the object that sends notifications (the provider); the Observer object represents the class that receives them (the observer).

The Subject class inherits both Observable and Observer, in the sense that it is both an observer and an observable. You can use a subject to subscribe all the observers, and then subscribe the subject to a backend data source

var subject = new Rx.Subject();

var subscription = subject.subscribe(
    function (x) { console.log('onNext: ' + x); },
    function (e) { console.log('onError: ' + e.message); },
    function () { console.log('onCompleted'); });

subject.onNext(1);
// => onNext: 1

subject.onNext(2);
// => onNext: 2

subject.onCompleted();
// => onCompleted

subscription.dispose();

More on https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/subjects.md

Solution 5

One thing I don't see in examples is that when you cast BehaviorSubject to Observable via asObservable, it inherits behaviour of returning last value on subscription.

It's the tricky bit, as often libraries will expose fields as observable (i.e. params in ActivatedRoute in Angular2), but may use Subject or BehaviorSubject behind the scenes. What they use would affect behaviour of subscribing.

See here http://jsbin.com/ziquxapubo/edit?html,js,console

let A = new Rx.Subject();
let B = new Rx.BehaviorSubject(0);

A.next(1);
B.next(1);

A.asObservable().subscribe(n => console.log('A', n));
B.asObservable().subscribe(n => console.log('B', n));

A.next(2);
B.next(2);
Share:
529,078
Kevin Mark
Author by

Kevin Mark

Front-End Developer

Updated on January 08, 2022

Comments

  • Kevin Mark
    Kevin Mark over 2 years

    I'm looking into Angular RxJs patterns and I don't understand the difference between a BehaviorSubject and an Observable.

    From my understanding, a BehaviorSubject is a value that can change over time (can be subscribed to and subscribers can receive updated results). This seems to be the exact same purpose of an Observable.

    When would you use an Observable vs a BehaviorSubject? Are there benefits to using a BehaviorSubject over an Observable or vice versa?

  • jmod999
    jmod999 over 7 years
    I am little bit confused with example 2 of regular subject. Why the subscription wont get anything even thoug on the second line you send values to subject using subject.next("b")?
  • Shantanu Bhadoria
    Shantanu Bhadoria about 7 years
    @jmod999 The second example is a regular subject which receives a value right before the subscription is called. In regular subjects, the subscription is only triggered for values received after subscription is called. Since a is received right before subscription, it is not sent to the subscription.
  • Jek
    Jek about 7 years
    what is the difference between subscription.dispose() and subscription.unsubscribe()?
  • Royi Namir
    Royi Namir about 7 years
    @choopage no difference. the latter is the new way
  • sam
    sam almost 7 years
    A note about that fantastic solution, if you use that in a function and return it, then return an observable. I had some issues with returning a subject, and it confuses the other developers that only know what are Observables
  • aruno
    aruno almost 7 years
    anyone coming from KnockoutJS's ko.observable() will immediately see more parallels to Rx.BehaviorSubject compared to Rx.Observable
  • JGFMK
    JGFMK over 6 years
    If you want to define it's type on a class property and import it too. Here's the skinny. import { BehaviorSubject } from 'rxjs/BehaviorSubject'; private message$:BehaviorSubject<string>; The marketplace VS Code extension I use - seems to have difficulty auto importing RxJS stuff for some reason...
  • Mohan Ram
    Mohan Ram over 6 years
    @Skeptor Observable: subscribe method will always trigger the onNext method associated with the observer and bring the return value. BehaviourSubject/Subject: Will always return the latest value in the stream. here subcribe method with the subject will not trigger onNext method of its Observer untill it finds the latest value in the stream.
  • bob.mazzo
    bob.mazzo over 6 years
    I had an Angular 4 interview on Wednesday. Since I'm still learning the new platform, he tripped me up by asking me something like "What's going to happen if I subscribe to an observable which is in a module that hasn't been lazy-loaded yet?" I wasn't sure, but he told me that the answer was to use a BSubject - EXACTLY how Mr Bhadoria explained it above. The answer was to use a BSubject because it always returns the latest value (at least that's how I remember the interviewer's final comment on that).
  • Rafael Reyes
    Rafael Reyes almost 6 years
    @bob.mazzo Why do I need to use a BSubject for that case? -- If I subscribe to that Observer I won´t receive anything because the observer hasn´t been initialized so it can't push data to observers and If I use a BSubject I won't either receive anything because of the same reason. In Both cases, the subscriber won´t receive anything because is within a module that hasn´t been initialized. Am I right?
  • bob.mazzo
    bob.mazzo almost 6 years
    @RafaelReyes - that was some months ago so the details of that interview escape me at the moment. However, I do recall reading that a BehaviorSubject will always have an initial value. Please verify that, however, as the interviewer's question was quite tricky.
  • ruffin
    ruffin over 5 years
    Why the giant image? If it's not directly related to your answer, it seems like votebait.
  • Zameer Ansari
    Zameer Ansari over 5 years
    @ruffin This is just an average answer with average number of votes, look at my profile. Not definitely votebait :D
  • ruffin
    ruffin over 5 years
    I gave you an upvote earlier, but you've dodged the question of why the image is there. It's not directly related to your answer. Doesn't matter if you've got a lot of rep or not -- if the image isn't directly and specifically elucidatory, I'd request you remove it. /shrug
  • Zameer Ansari
    Zameer Ansari over 5 years
    @ruffin If it goes against the community consent, then it shouldn't be there surely!
  • Sophie Zhang
    Sophie Zhang over 5 years
    Should unsubscribe before the subject is disposed, otherwise, the subscription becomes a garbage since it subscribes to a null value.
  • Emobe
    Emobe almost 5 years
    shouldn't the service have a private BehaviourSubject and the value is accessed from a public Observable which emits the value of the BehaviourSubject, so not to allow next being called on the BS outside of the service?
  • gvivetapl
    gvivetapl almost 5 years
    I'm a little confused about the use of BehiavorSubject instead of using shared variables in a service. If I create a service with shared variables and even overwrite them, the angular components also detect these changes, then why should I use BehiavorSubject instead of shared variables? for example, an array.
  • Johnathan Li
    Johnathan Li over 4 years
    @RafaelReyes No, that is no the same. If you use BahaviourObject which means that after You subscribed you will immediately get the data which you pass in before the subscription. So you do not need to pass the data again after subscription. It is pretty well present in the example tho.
  • Johnathan Li
    Johnathan Li over 4 years
    @gvivetapl It is because if you use Observable you can access tons of RXJS operations after you subscribe an value.
  • Wilt
    Wilt over 4 years
    Could be worth mentioning that a ReplaySubject has a history and can broadcast/emit a sequence of (old) values. Only when buffer is set to 1 it is behaving similar to a BehaviorSubject.
  • Jaqen H'ghar
    Jaqen H'ghar over 3 years
    For BehaviorSubject the paragraph "Replay the message stream" seems not correct
  • Jeb50
    Jeb50 about 3 years
    covers many parts, but the bright side of your explanation is giving an easy-to-understand analogy, Kudo!!!