🐶
Angular

BehaviorSubject vs Observable in Angular: Key Differences

By Filip on 10/05/2024

This article examines the key differences between BehaviorSubject and Observable in Angular, focusing on their initialization, value emission, and use cases for reactive programming.

BehaviorSubject vs Observable in Angular: Key Differences

Table of Contents

Introduction

In the realm of reactive programming with RxJS, understanding the nuances of Observables, Subjects, and BehaviorSubject is crucial. This article provides a breakdown of these core concepts, highlighting their differences and use cases. We'll explore how Observables serve as the foundation for asynchronous data streams, while Subjects introduce the power of multicasting. Further, we'll delve into BehaviorSubject, a specialized Subject that retains and broadcasts the latest emitted value. By the end, you'll have a clear understanding of when to employ each for effective reactive programming.

Step-by-Step Guide

Let's break down the differences between Observables, Subjects, and BehaviorSubject in RxJS.

1. Observables: The Foundation

Imagine an Observable as a pipe delivering data over time. You subscribe to this pipe to receive the data.

const observable = new Observable(subscriber => {
  subscriber.next(1);
  subscriber.next(2);
  subscriber.next(3);
  subscriber.complete();
});

observable.subscribe(value => {
  console.log('Received:', value);
});

In this example, the Observable emits 1, 2, and 3, then signals completion. Each subscriber gets these values as they are emitted.

2. Subjects: The Multicasting Bridge

A Subject acts like both an Observable and an observer. It can emit data like an Observable and be subscribed to. The key difference is that it multicasts the data to all its subscribers simultaneously.

const subject = new Subject();

subject.subscribe(value => console.log('Observer 1:', value));
subject.subscribe(value => console.log('Observer 2:', value));

subject.next(1); 
subject.next(2);

Both observers will receive 1 and then 2.

3. BehaviorSubject: Remembering the Past

A BehaviorSubject is a special type of Subject that always remembers the last emitted value. When a new subscriber joins, it immediately receives this latest value.

const subject = new BehaviorSubject(0); // Initial value is 0

subject.subscribe(value => console.log('Observer 1:', value));

subject.next(1); 
subject.next(2);

subject.subscribe(value => console.log('Observer 2:', value)); // Late subscriber
  • Observer 1 will see: 0, 1, 2
  • Observer 2 will see: 2 (the latest value)

Key Differences and When to Use Each:

  • Observable: Use for data streams where each subscriber gets its own independent flow of values.
  • Subject: Use when you need to multicast data to multiple subscribers at the same time.
  • BehaviorSubject: Use when you need to keep track of the latest value and provide it to new subscribers immediately.

In Essence:

  • Observables are like newsletters – each subscriber gets their own copy.
  • Subjects are like radio broadcasts – everyone tuned in hears the same thing.
  • BehaviorSubjects are like message boards with sticky notes – the latest message is always visible.

Code Example

The code demonstrates the differences between Observables, Subjects, and BehaviorSubjects in RxJS. It shows how Observables emit values to each subscriber independently, Subjects multicast values to all subscribers, and BehaviorSubjects provide the last emitted value to new subscribers.

// 1. Observables: The Foundation
const observable = new Observable(subscriber => {
  console.log('Observable starts emitting values');
  subscriber.next(1);
  subscriber.next(2);
  subscriber.next(3);
  subscriber.complete();
});

console.log('Subscribing to Observable 1:');
observable.subscribe(value => {
  console.log('  Observable 1 received:', value);
});

console.log('Subscribing to Observable 2:');
observable.subscribe(value => {
  console.log('  Observable 2 received:', value);
});

// 2. Subjects: The Multicasting Bridge
const subject = new Subject();

console.log('\nSubscribing to Subject 1:');
subject.subscribe(value => console.log('  Subject 1 received:', value));

console.log('Subscribing to Subject 2:');
subject.subscribe(value => console.log('  Subject 2 received:', value));

console.log('Sending values to Subject:');
subject.next(1); 
subject.next(2);

// 3. BehaviorSubject: Remembering the Past
const behaviorSubject = new BehaviorSubject(0); // Initial value is 0

console.log('\nSubscribing to BehaviorSubject 1:');
behaviorSubject.subscribe(value => console.log('  BehaviorSubject 1 received:', value));

console.log('Sending values to BehaviorSubject:');
behaviorSubject.next(1); 
behaviorSubject.next(2);

console.log('Subscribing to BehaviorSubject 2:');
behaviorSubject.subscribe(value => console.log('  BehaviorSubject 2 received:', value)); // Late subscriber

Output:

Subscribing to Observable 1:
Observable starts emitting values
  Observable 1 received: 1
  Observable 1 received: 2
  Observable 1 received: 3
Subscribing to Observable 2:
Observable starts emitting values
  Observable 2 received: 1
  Observable 2 received: 2
  Observable 2 received: 3

Subscribing to Subject 1:
Subscribing to Subject 2:
Sending values to Subject:
  Subject 1 received: 1
  Subject 2 received: 1
  Subject 1 received: 2
  Subject 2 received: 2

Subscribing to BehaviorSubject 1:
  BehaviorSubject 1 received: 0
Sending values to BehaviorSubject:
  BehaviorSubject 1 received: 1
  BehaviorSubject 1 received: 2
Subscribing to BehaviorSubject 2:
  BehaviorSubject 2 received: 2 

Explanation:

  1. Observables: Each subscription triggers the Observable to emit its values from the beginning. Notice how "Observable starts emitting values" is printed twice.
  2. Subjects: Both subscribers receive the values 1 and 2 simultaneously because the Subject multicasts the data.
  3. BehaviorSubjects: The first subscriber sees all values (including the initial value 0). The second subscriber, joining later, only receives the latest value (2) because that's what the BehaviorSubject remembers.

Additional Notes

Observables:

  • Lazy Evaluation: Observables only start working (emitting values) when you subscribe to them. This is crucial for efficiency, especially with resource-intensive operations.
  • Operators: The real power of Observables lies in using operators (like map, filter, mergeMap) to transform, combine, and manipulate data streams.
  • Error Handling: Observables have built-in error handling using the error notification and the catchError operator.
  • Unsubscribing: Always remember to unsubscribe from Observables when you're done with them to prevent memory leaks.

Subjects:

  • Direct Control: Subjects give you direct control over emitting values, making them suitable for bridging between imperative and reactive code.
  • Use Cases: Common use cases include:
    • Sharing data between components that don't have a direct parent-child relationship.
    • Implementing event buses or message brokers.
  • Caution: Overusing Subjects can make your code harder to reason about. Consider if a regular Observable with operators would be a better fit.

BehaviorSubject:

  • Initial Value: The requirement to provide an initial value ensures that subscribers always have something to work with, even before the first emission.
  • State Management: BehaviorSubjects are often used in simple state management solutions where you need to keep track of the latest state and notify subscribers about changes.
  • Alternatives: For more complex state management, consider dedicated libraries like Redux, NgRx, or Zustand.

General Tips:

  • Start Simple: Begin with Observables and only introduce Subjects and BehaviorSubjects when you have a specific need for their capabilities.
  • Choose Wisely: Carefully consider the trade-offs between each type and select the one that best suits your use case.
  • Testing: Observables, Subjects, and BehaviorSubjects are highly testable. Use marble testing techniques to write concise and effective tests for your reactive code.

Summary

Feature Observable Subject BehaviorSubject
Type Data stream Multicasting Observable State-carrying Subject
Data Sharing Independent for each subscriber Shared among all subscribers Shared, with latest value remembered
New Subscriber Behavior Receives values from subscription time Receives values from subscription time Immediately receives the latest emitted value
Use Cases - Individual data flows
- HTTP requests
- Real-time updates
- Event handling
- Maintaining shared state
- Caching latest values
Analogy Newsletter (each subscriber gets their own copy) Radio broadcast (everyone hears the same thing) Message board with sticky notes (latest message always visible)

In short:

  • Observables are for independent data streams.
  • Subjects are for multicasting data to multiple subscribers.
  • BehaviorSubjects are for sharing the latest value with new subscribers immediately.

Conclusion

Choosing the right tool for the job is key in reactive programming. Observables provide a robust foundation for handling asynchronous data streams, while Subjects introduce multicasting capabilities. When you need to persist the latest emitted value and make it available to late subscribers, BehaviorSubject comes into play. By understanding the strengths and use cases of each, you can leverage the power of RxJS to build reactive and efficient applications.

References

Were You Able to Follow the Instructions?

😍Love it!
😊Yes
😐Meh-gical
😞No
🤮Clickbait