October 15, 2021

Angular - Observables vs Subjects vs Behavior Subjects

In this post I will explain different observables with example that would help you to understand what actually is the observable and which type of observable should you use in different scenarios where it makes more sense.

Observables are asynchronous stream of data, emit values over time. It is just a container of values you can subscribe, to receive data when available.

Observables provide support for passing messages between parts of your application. They are used frequently in Angular and are a technique for event handling, asynchronous programming, and handling multiple values.

We have different types of observables avilable in RxJS Library, lets explore each one.

Observable

Basically its just a function, and do not maintain state. Observable will not execute until we subscribe to them using the subscribe() method. It emits three types of notifications, i.e. next, error and complete. Observable code is run for each observer, i.e. if it is making an HTTP request, then that request will be called for each observer/subscribers, hence not a single instance of data is shared, but each obeserver will receive a copy of data. The observer(subscriber) could not assign a value to observable, it can only consume the data.

Lets see an example, first define the observer using the constructor new Observable().

let obs = new Observable((observer) => {
  
  setTimeout(() => { observer.next("1") }, 1000);
  setTimeout(() => { observer.next("2") }, 1000);
  setTimeout(() => { observer.next("3") }, 1000);
  //setTimeout(() => { observer.error("error emitted") }, 1000);    //send error event. observable stops here
  //setTimeout(() => { observer.complete() }, 1000);   //send complete event. observable stops here
  setTimeout(() => { observer.next("4") }, 1000);          //this code is never called, if error or complete event is triggered
  setTimeout(() => { observer.next("5") }, 1000);

})

This observer is emitting values on an interval of 1 second.

There are many operators available with the RxJS library, which makes the task of creating the observable easy. Using these operators you can create observable from an array, string, promise, any iterable, etc. Some of these operators are create, defer, empty, from, fromEvent, interval, of, range, throwError, timer.

Remember that observable will not execute until we subscribe to it. Here we subscribe to all 3 notifications i.e. next, error and complete.

obs.subscribe(
  val=> { console.log('next value received from observer: ' + val) },
  error => { console.log("error event received from observable")},
  () => {console.log("completed event received from observable")}
)

In our Observable definition, we have commented out the lines for error and complete events. Whenver any of these event is triggered, the observable will stop running, so you will not receive any more values if the error or complete event is triggerd on an obeservable.

Subject:

It is technically a sub-type of Observable because Subject is an observable with specific qualities. Subjects are also asynchronous stream of data, emit values. The observer need to subscribe to the Subject in order to receive notifications. The observer would start to receive the values after subscription, and all prior values that might emitted before, would be missed. Observer also have the option to assign value to the observable(Subject). Unlike observable mentioned in previous exmaple, the same code will run for all observers and hence the same data will be shared between all observers.

Lets see an exmaple for Subject,

let subject = new Subject(); 

//subject emits first value, but this will be missed, because till here we have not subscribed to this subject.
subject.next("b");

//first subscription to the subject
subject.subscribe(value => {
  console.log("Subscription received value: ", value); // Subscription wont get anything at this point, the first value "b" emitted above, is missed.
});

//subject emit more values, this time we already have one subscription, so it will receive these values.
subject.next("c"); 
subject.next("d"); 

BehaviorSubject:

It is a special type of Subject, a Subject that requires an initial value and emits its current value to new subscribers. It stores data in memory, and same code run only once for all observers so the same data is shared to all observers. Since it needs an initial value, so it always return a value on subscription even if it hasn't received a next(). Unlike the Subject, once an observer subscribe to it, the observer will immediately receive the current value without having to wait for future next() call.

Lets see an example for BehaviorSubject:

//BehaviorSubject is initialized with initial value "a" through its constructor
let bSubject = new BehaviorSubject("a"); 

//BehaviorSubject emits second value, so the current value here is "b". But still we dont have any subscription.
bSubject.next("b");

//first subscription to the BehaviorSubject, soon we subscribe, the current value "b" will be received.
bSubject.subscribe(value => {
  console.log("Subscription received value: ", value); // Subscription got current value "b", 
});

//BehaviorSubject emit more values, that will be received by our subscription.
bSubject.next("c"); 
bSubject.next("d"); 

ReplaySubject

It is another special type of Subject, a Subject that wil replay the message stream. It stores data in memory, and same code run only once for all observers so the same data is shared to all observers. Unlike the BehaviorSubject, once an observer subscribe to it, the observer will receive the all the previous values that might have emitted before its subscription. No matter when you subscribe the replay subject, you will receive all the broadcasted messages.

Lets see an example:

let rSubject = new ReplaySubject(); 

//ReplaySubject emits three values "a", "b" and "c". But still we dont have any subscription.
rSubject.next("a");
rSubject.next("b");
rSubject.next("c");

rSubject.subscribe(value => {
  console.log("Subscription received value: ", value); // Subscription will get all three values "a", "b" and "c".
});

//ReplaySubject emit more values, that will be received by our subscription.
rSubject.next("d"); 
rSubject.next("e"); 

References:

1 comment:

  1. Wonderful blog & good post.Its really helpful for me, awaiting for more new post. Keep Blogging!
    Offshore Angularjs Development Company – Nintriva

    ReplyDelete