What is the difference between BehaviorSubject and Observable?
Asked Answered
P

14

1028

I'm looking into the design patterns of RxJS, and I do not understand the difference between BehaviorSubject and Observable.

From my understanding, BehaviorSubject can contain a value that may change. It can be subscribed to and subscribers can receive updated values. Both seem to have the exact same purpose.

  1. When should one use Observable vs BehaviorSubject, and vice versa?
  2. What are the benefits of using BehaviorSubject as opposed to Observable, and vice versa?
Pipe answered 14/9, 2016 at 15:14 Comment(1)
This article especially helped me understand observables vs subjects vs behavior subjects in ELI5 way javascript.plainenglish.io/…Heterogamy
A
1402

BehaviorSubject is a variant of Subject, a type of Observable to which one can "subscribe" like any other Observable.

Features of BehaviorSubject

  • It needs an initial value as it must always return a value upon subscription, even if it has not received the method next()
  • Upon subscription, it returns the last value of the Subject. A regular Observable is only triggered when it receives the method onNext()
  • At any point, one can retrieve the last value of the Subject in a non-Observable using the method getValue()

Features of Subject

  • Subject is an "observer" in addition to being an Observable; therefore, one can also send values to a Subject while also subscribing to it
  • One can get a value from BehaviorSubject using the method asObservable()

Example 1 using BehaviorSubject

// BehaviorSubject.
// 'A' is an initial value. If there is a Subscription 
// after it, it would immediately get the value 'A'.

beSubject = new BehaviorSubject('a'); 

beSubject.next('b');

beSubject.subscribe(value => {
  console.log('Subscription received the value ', value);

  // Subscription received B. It would not happen
  // for an Observable or Subject by default.
});

beSubject.next('c');
// Subscription received C.

beSubject.next('d');
// Subscription received D.

Example 2 using Subject

// Subject.

subject = new Subject(); 

subject.next('b');

subject.subscribe(value => {
  console.log('Subscription received the value ', value);

  // Subscription won't receive anything at this point.
});

subject.next('c');
// Subscription received C.

subject.next('d');
// Subscription received D.

An Observable can be created from both Subject and BehaviorSubject; for example, subjectName.asObservable().

The only difference is that one cannot send values to an Observable using the method next().

In Angular, it is recommended to use BehaviorSubject for transferring data as a Service is often initialised before a component.

BehaviorSubject ensures that the component consuming the Service receives the last updated data, even if there are no new updates, due to the subscription of the component to the Service.

Anny answered 25/10, 2016 at 4:53 Comment(11)
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")?Tintoretto
@Tintoretto 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.Anny
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 ObservablesLaurentian
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...Pollerd
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).Canebrake
@Canebrake 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?Vamp
@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.Canebrake
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?Graz
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.Libbey
@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.Selfpollination
@Libbey It is because if you use Observable you can access tons of RXJS operations after you subscribe an value.Selfpollination
R
274

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                          ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
Reubenreuchlin answered 17/6, 2017 at 3:19 Comment(2)
anyone coming from KnockoutJS's ko.observable() will immediately see more parallels to Rx.BehaviorSubject compared to Rx.ObservableMozzetta
@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.Should
D
133

Observable and Subject are both observable's, which means an observer can track them. Both of them have some unique characteristics. There are a 3 types of Subjects, each of which also have unique characteristics.

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 you are 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 ReplaySubject, you cannot set the initial value to observable. So here comes BehavioralSubject...

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

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

Depside answered 17/11, 2018 at 21:47 Comment(2)
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.Mixon
Using BehaviorSubject you can get the current value with the property value. It works differently than method subscribe. The value property pull the value, the subscribe method listen values pushed from the ObservableF
E
36

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

Energetic answered 14/9, 2016 at 15:27 Comment(3)
what is the difference between subscription.dispose() and subscription.unsubscribe()?Starnes
@choopage no difference. the latter is the new wayTrossachs
Should unsubscribe before the subject is disposed, otherwise, the subscription becomes a garbage since it subscribes to a null value.Excruciation
R
22

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);
Revolutionize answered 5/9, 2017 at 14:59 Comment(0)
S
17

An observable allows you to subscribe only whereas a subject allows you to both publish and subscribe.

So a subject allows your services to be used as both a publisher and a subscriber.

As of now, I'm not so good at Observable so I'll share only an example of Subject.

Let's understand better with an Angular CLI example. Run the below commands:

npm install -g @angular/cli

ng new angular2-subject

cd angular2-subject

ng serve

Replace the content of app.component.html with:

<div *ngIf="message">
  {{message}}
</div>

<app-home>
</app-home>

Run the command ng g c components/home to generate the home component. Replace the content of home.component.html with:

<input type="text" placeholder="Enter message" #message>
<button type="button" (click)="setMessage(message)" >Send message</button>

#message is the local variable here. Add a property message: string; to the app.component.ts's class.

Run this command ng g s service/message. This will generate a service at src\app\service\message.service.ts. Provide this service to the app.

Import Subject into MessageService. Add a subject too. The final code shall look like this:

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';

@Injectable()
export class MessageService {

  public message = new Subject<string>();

  setMessage(value: string) {
    this.message.next(value); //it is publishing this value to all the subscribers that have already subscribed to this message
  }
}

Now, inject this service in home.component.ts and pass an instance of it to the constructor. Do this for app.component.ts too. Use this service instance for passing the value of #message to the service function setMessage:

import { Component } from '@angular/core';
import { MessageService } from '../../service/message.service';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent {

  constructor(public messageService:MessageService) { }

  setMessage(event) {
    console.log(event.value);
    this.messageService.setMessage(event.value);
  }
}

Inside app.component.ts, subscribe and unsubscribe (to prevent memory leaks) to the Subject:

import { Component, OnDestroy } from '@angular/core';
import { MessageService } from './service/message.service';
import { Subscription } from 'rxjs/Subscription';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent {

  message: string;
  subscription: Subscription;

  constructor(public messageService: MessageService) { }

  ngOnInit() {
    this.subscription = this.messageService.message.subscribe(
      (message) => {
        this.message = message;
      }
    );
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}

That's it.

Now, any value entered inside #message of home.component.html shall be printed to {{message}} inside app.component.html

Shipp answered 24/1, 2018 at 6:44 Comment(4)
Why the giant image? If it's not directly related to your answer, it seems like votebait.Sheepdog
@Sheepdog This is just an average answer with average number of votes, look at my profile. Not definitely votebait :DShipp
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. /shrugSheepdog
@Sheepdog If it goes against the community consent, then it shouldn't be there surely!Shipp
M
14

Think of Observables as a pipe with flowing water in it, sometimes water flows and sometimes it doesn't. In some cases, you may actually need a pipe that has always water in it, you can do this by creating a special pipe which always contains a water no matter how small it is, lets call this special pipe BehaviorSubject, if you happens to be a water supply provider in your community, you can sleep peacefully at night knowing that your newly installed pipe just works.

In technical terms: you may encounter usescases where an Observable should always have value in it, perhaps you want to capture the value of a input text over time, you can then create an instance of BehaviorSubject to ensure this kind of behavior, lets say:


const firstNameChanges = new BehaviorSubject("<empty>");

// pass value changes.
firstNameChanges.next("Jon");
firstNameChanges.next("Arya");

You can then use "value" to sample changes over time.


firstNameChanges.value;

This comes handy when you combine Observables later, by taking a look at the type of your stream as BehaviorSubject you can then ensure that the stream at least fires or signal just once atleast.

Mallard answered 9/5, 2020 at 3:56 Comment(2)
covers many parts, but the bright side of your explanation is giving an easy-to-understand analogy, Kudo!!!Cadre
i like analogiesNummary
C
10

app.component.ts

behaviourService.setName("behaviour");

behaviour.service.ts

private name = new BehaviorSubject("");
getName = this.name.asObservable();

constructor() {}

setName(data) {
    this.name.next(data);
}

custom.component.ts

behaviourService.subscribe(response=>{
    console.log(response);    //output: behaviour
});
Clapp answered 11/12, 2018 at 13:3 Comment(1)
This is an encapsulation: The main reason for converting a BehaviorSubject to an Observable when exposing it publicly (like with getName) is to prevent external consumers from being able to push values into your subject. By only providing the Observable version, you ensure that external components can only listen to the values but cannot change them. This provides better control over the data flow in your application.Nummary
P
6

BehaviorSubject vs Observable : RxJS has observers and observables, Rxjs offers a multiple classes to use with data streams, and one of them is a BehaviorSubject.

Observables : Observables are lazy collections of multiple values over time.

BehaviorSubject:A Subject that requires an initial value and emits its current value to new subscribers.

 // RxJS v6+
import { BehaviorSubject } from 'rxjs';

const subject = new BehaviorSubject(123);

//two new subscribers will get initial value => output: 123, 123
subject.subscribe(console.log);
subject.subscribe(console.log);

//two subscribers will get new value => output: 456, 456
subject.next(456);

//new subscriber will get latest value (456) => output: 456
subject.subscribe(console.log);

//all three subscribers will get new value => output: 789, 789, 789
subject.next(789);

// output: 123, 123, 456, 456, 456, 789, 789, 789
Peckham answered 3/4, 2019 at 10:52 Comment(0)
T
5

Observable is a Generic,

Observables are lazy collections of multiple values over time.

Is just a function, no state

Code run for each observer

BehaviorSubject: A Subject that requires an initial value and emits its current value to new subscribers.

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

Has state. Stores data in memory

Same code run only once for all observers

The unique features of BehaviorSubject are following:

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.

Thallophyte answered 23/3, 2021 at 17:33 Comment(0)
L
5

Subject in rxjs is essentially an observer and observable masheed together. Observer is something that we throw in values, observable is something that we can watch for values.

  • Subject is Hot by default. Observables by default are cold. That means they are not going to emit any values until someone subscribes to it. The instant we create a subject, we can emit a value from it and that value will be emitted even if nobody is subscribed to it yet.
  • Subject is multicast by default. Observable by default are unicast and that means that for every different observer that we have, we have to subscibe to an observable, if that observable emits a value that value is going to flow through all the different operators inside of our pipe once for each subscriber. Multicast means all of other operators will run one time for every value, regardless of the number of observers we have.
  • GOTCHA= thE SUBJECT is multicast but if you chain on a pipe statement to it, that is going to return a new observable that is cold and unicast.

Behaviour subject is same as subject, but also takes an initial "seed" value. New subscribers instantly get the most recent value. If someone ever subscribes to Behavior subject, it is going to instantly receive whatever the most recent value was. So the behavior subject is always going to have some value to give out to a subscriber.

The most useful thing about a behavior subject is when we start making network requests. Imagine that we chained on some piping stuff to a behavior subject and inside a pipe function or a pipe operator, we end up making a network request and fetching some data. You might eventually want to have something else subscribe to that observable and immediately get the data have been already fetched. Using a behavior subject, we can implement that kind of behavior easily.

Lowdown answered 13/12, 2021 at 2:58 Comment(0)
K
2

BehaviorSubject

The BehaviorSubject builds on top of the same functionality as our ReplaySubject, subject like, hot, and replays previous value.

The BehaviorSubject adds one more piece of functionality in that you can give the BehaviorSubject an initial value. Let’s go ahead and take a look at that code

import { ReplaySubject } from 'rxjs';

const behaviorSubject = new BehaviorSubject(
  'hello initial value from BehaviorSubject'
);

behaviorSubject.subscribe(v => console.log(v));

behaviorSubject.next('hello again from BehaviorSubject');

Observables

To get started we are going to look at the minimal API to create a regular Observable. There are a couple of ways to create an Observable. The way we will create our Observable is by instantiating the class. Other operators can simplify this, but we will want to compare the instantiation step to our different Observable types

import { Observable } from 'rxjs';

const observable = new Observable(observer => {
  setTimeout(() => observer.next('hello from Observable!'), 1000);
});

observable.subscribe(v => console.log(v));
Korney answered 23/7, 2020 at 10:16 Comment(0)
J
2

I think Observable as a wrapper around the Subject. While Observable used only to subscribe to the data changes. Subject can also be used to notify the data changes to subscribers (using next() method). Here is a small observable pattern implementation which might help you to understand the concept. TypeScript Playground

Joplin answered 25/3, 2022 at 15:51 Comment(0)
R
0

Just to be clear you also can change an subject to an observable like this:

 page = new BehaviorSubject<String|null>(null);
 actualPage:Observable<string> = new Observable()

this.page.next("hardware")
this.actualPage = this.page as Observable<any>;
Raddled answered 21/4, 2022 at 12:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.