BehaviorSubject vs Observable?
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 won't 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.
What is the difference between Subject and BehaviorSubject?
A BehaviorSubject holds one value. When it is subscribed it emits the value immediately. A Subject doesn't hold a value.
Subject example (with RxJS 5 API):
const subject = new Rx.Subject();
subject.next(1);
subject.subscribe(x => console.log(x));
Console output will be empty
BehaviorSubject example:
const subject = new Rx.BehaviorSubject(0);
subject.next(1);
subject.subscribe(x => console.log(x));
Console output: 1
In addition:
BehaviorSubject
should be created with an initial value: newRx.BehaviorSubject(1)
- Consider
ReplaySubject
if you want the subject to get previously publised values.
Subject vs BehaviorSubject vs ReplaySubject in Angular
It really comes down to behavior and semantics. With a
Subject
- a subscriber will only get published values that were emitted after the subscription. Ask yourself, is that what you want? Does the subscriber need to know anything about previous values? If not, then you can use this, otherwise choose one of the others. For example, with component-to-component communication. Say you have a component that publishes events for other components on a button click. You can use a service with a subject to communicate.BehaviorSubject
- the last value is cached. A subscriber will get the latest value upon initial subscription. The semantics for this subject is to represent a value that changes over time. For example a logged in user. The initial user might be an anonymous user. But once a user logs in, then the new value is the authenticated user state.The
BehaviorSubject
is initialized with an initial value. This is sometimes important to coding preference. Say for instance you initialize it with anull
. Then in your subscription, you need to do a null check. Maybe OK, or maybe annoying.ReplaySubject
- it can cache up to a specified number of emissions. Any subscribers will get all the cached values upon subscription. When would you need this behavior? Honestly, I have not had any need for such behavior, except for the following case:If you initialize a
ReplaySubject
with a buffer size of1
, then it actually behaves just like aBehaviorSubject
. The last value is always cached, so it acts like a value changing over time. With this, there is no need for anull
check like in the case of theBehaviorSubject
initialized with anull
. In this instance, no value is ever emitted to the subscriber until the first publishing.
So it really comes down to the behavior you are expecting (as for which one to use). Most of the time you will probably want to use a BehaviorSubject
because what you really want to represent is that "value over time" semantic. But I personally don't see anything wrong with the substitution of ReplaySubject
initialized with 1
.
What you want to avoid is using the vanilla Subject
when what you really need is some caching behavior. Take for example you are writing a routing guard or a resolve. You fetch some data in that guard and set it in a service Subject
. Then in the routed component you subscribe to the service subject to try to get that value that was emitted in the guard. OOPs. Where's the value? It was already emitted, DUH. Use a "caching" subject!
See also:
- What are RxJS Subject's and the benefits of using them?
How to Subscribe a Behavior Subject with an Observable
When you want to get that behavior you should use the observable you've got and share it + replay the last value. Good thing is, there's an operator for that: shareReplay
.
Important note: define the params of shareReplay otherwise you'll replay an infinite number of values and if no one listen to the observable anymore.. It'll still be kept open!
So do the following:
const replayedObs$ = originalObs$.pipe(
shareReplay({ bufferSize: 1, refCount: true })
)
this way you'll only get the latest value when you subscribe AND if no one listen to the replayedObs$
anymore it'll be closed.
Related Topics
How to Read an External Local Json File in JavaScript
Managing Jquery Plugin Dependency in Webpack
JavaScript Inheritance and the Constructor Property
Delete Firebase Data Older Than 2 Hours
How to Get the Difference Between Two Dates in JavaScript
Html5 Video - Percentage Loaded
CSS Selector for Targeting Only Immediate Children and Not Other Identical Descendants
Add a Transform Value to the Current Transforms That Are Already on the Element
Viable Options for Running Nodejs on Android (Aug 2017)
Get Contenteditable Caret Position
How to Get the Coordinates of a Mouse Click on a Canvas Element
How to Check If a Variable Is an Array in JavaScript
Merge Two Array of Objects Based on a Key
How Does This Object Method Definition Work Without the "Function" Keyword
Is "Clear" a Reserved Word in JavaScript
Padding or Margin Value in Pixels as Integer Using Jquery