845
votes

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?

11

11 Answers

1188
votes

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.

227
votes

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                          ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
83
votes

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.

31
votes

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

21
votes

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);
15
votes

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

5
votes

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.

4
votes

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
});
1
votes

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
0
votes

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));
0
votes

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.