ReviseAlgo Logo

RxJS

Subject

Master RxJS Subjects, covering unicast vs multicast execution, using Subjects as both Observables and Observers, and managing state.

Last Updated: July 15, 2026 11 min read

1. Learning Objectives

In this lesson, you will master the RxJS Subject, a special type of Observable that enables multi-casting. By the end of this topic, you will be able to:

  • Differentiate between Unicast execution (Observables) and Multicast execution (Subjects).
  • Explain the dual nature of a Subject acting as both an Observable and an Observer.
  • Create and subscribe multiple independent Observers to a shared Subject instance.
  • Use a Subject as an event bus to coordinate communication across distant components.
  • Identify situations where a plain Subject is insufficient due to lack of state caching.

2. Overview

A Subject is a special type of Observable in RxJS that allows values to be multicasted to many Observers. While a standard Observable is **unicast** (each subscriber initiates a new, independent execution of the producer), a Subject is **multicast** (the producer is shared, and all subscribers receive the exact same values simultaneously). Additionally, a Subject implements the Observer interface, meaning you can manually call .next(), .error(), and .complete() on it directly.

3. Why This Topic Matters

Understanding Subjects is crucial for managing application state and sharing data streams:

  • Sharing Expensive Workloads: If an Observable fetches data from an HTTP API or connects to a websocket, subscribing to it 3 times triggers 3 network connections. Wrapping it in a Subject shares a single socket or request among all subscribers.
  • Component Inter-communication: When non-related components need to talk (e.g. clicking a button in header collapses a sidebar), a shared Subject acts as a lightweight event broker.

4. Real-World Analogy

Let's contrast standard Observables and Subjects using real-world communication:

  • Unicast (Standard Observable) is like a Netflix Video: When you hit play, you start watching from the beginning. If your friend hits play 10 minutes later, they start watching from their own beginning. You are not sharing the stream progress.
  • Multicast (Subject) is like a Live Concert: The band performs in real-time. If you arrive late, you only hear what's being played right then. You missed the opening song. Your friend who arrived on time heard everything, but both of you are listening to the exact same audio stream at the same moment.

5. Core Concepts

Subjects operate on unique principles:

  • Observer Role: Subject has next(v), error(e), and complete() methods. You can pass a Subject directly as the argument to another observable's .subscribe() call.
  • Observable Role: Subject has a subscribe() method. Consumers register callbacks on it.
  • No Value Caching: A plain Subject does not remember any historical values. Late subscribers receive nothing until a new .next() event is triggered.
Property Observable Subject
Execution Model Unicast (1 to 1) Multicast (1 to many)
Side Effects Triggered On every subscription call Shared once; no redundant executions
Manual Emitting No (Producer logic isolated inside constructor) Yes (Via `.next()` method call)

6. Syntax & API Reference

This is the syntax for creating and executing a Subject:

7. Visual Diagram

The diagram below demonstrates multicasting using a Subject:

8. Live Example — Full Working Code

Below is a global notification event bus service that allows components to broadcast text alerts to a central notification banner:

What just happened? Any component in the app can inject NotificationBusService and call triggerAlert('Data saved!'). The shared Subject broadcasts this string, and the central NotificationBannerComponent receives it reactively, displaying a warning banner.

9. Interactive Playground

Try It Yourself Challenges:

  1. Modify the event bus so that if the Subject receives a complete() notification, it closes the banner indefinitely.
  2. Mount two independent NotificationBannerComponent components on the page and verify they receive the same notification message simultaneously.

10. Common Mistakes

Mistake Why it happens Wrong Correct
Expecting Caching from Plain Subjects Assuming late subscribers will get the last message. Plain Subjects have no cache. sub.next('State'); sub.subscribe(v => ...) Use BehaviorSubject for state persistence.
Leaving Subject Public Exposing raw Subject lets external code call .next() and pollute the stream. public state$ = new Subject(); private sub = new Subject(); public state$ = sub.asObservable();

11. Best Practices

  • Encapsulate subject mutations: Keep the Subject reference private inside services. Expose it via asObservable() to ensure only the service manages state emissions.
  • Unsubscribe properly: Even though the subject multicast reduces side effects, subscribers must still release their connections to prevent leaks.
  • Choose Subject types wisely: Use plain Subject only for transient events (e.g. button clicks, alerts). Use BehaviorSubject for data state.

12. Browser Compatibility/Requirements

Subjects are implemented as custom Javascript classes. They run on all modern ES6 compatible browsers and require no polyfills.

13. Interview Questions

Q1: What is the main difference between an Observable and a Subject?

Answer: An Observable is unicast (each observer receives a private execution of the source producer). A Subject is multicast (all observers share a single execution of the source and receive the same values). Additionally, a Subject acts as both an Observer (you can call next() on it) and an Observable.

Q2: Why do late subscribers to a plain Subject receive undefined or empty responses?

Answer: A plain Subject does not store the emitted values in memory. It immediately forwards values to existing subscribers and discards them. If a subscriber registers after an emission, they receive nothing until the next value is emitted.

14. Debugging Exercise

Identify why Component B is not logging the initial state message 'Active' when subscribing:

View Solution

Diagnosis: A plain Subject has no memory. Because the stateBus.next('Active') emission happened *before* Component B subscribed, the value is missed.

Fix: Switch to a BehaviorSubject which caches the last value and immediately plays it to new subscribers, or subscribe before emitting.

15. Practice Exercises

Exercise 1: Create a multicasted API cache

Build an Angular service that fetches data from an HTTP client. Subscribe 3 components to this stream. Use a Subject to share the execution, verifying in your developer tools network tab that only 1 HTTP request is made.

16. Scenario-Based Challenge

The Multi-Client Websocket Hub:

You are designing a real-time stock pricing dashboard with multiple panels. If 5 panels subscribe to a websocket stock price stream individually, they'll create 5 websocket connections. Design a service using a Subject that establishes a single websocket connection, multicasting the incoming pricing data to all active panels.

17. Quick Quiz

Q1: Which pattern describes an execution model where every subscriber gets a separate data producer?

A) Multicast

B) Unicast

C) Broadcast

Answer: B — Unicast assigns a single producer execution per observer subscription.

18. Summary & Key Takeaways

  • Subjects multicast values to multiple observers, sharing the underlying producer.
  • A Subject can act as both an Observable (subscribed to) and an Observer (emit events with .next()).
  • Standard Subjects do not cache values. Late subscribers miss past events.
  • Exposing Subjects via .asObservable() keeps data streams read-only outside of service boundaries.

19. Cheat Sheet

Syntax / Method Description
new Subject<T>() Creates a new, un-cached multicast event bus.
subject.next(value) Manually publishes a value to all registered subscribers.
subject.asObservable() Hides the Subject methods (next/error/complete) from API consumers.
---