Briebug Blog

Sharing our thoughts with the community

What is the difference between a Subject and an Observable?

What is the difference between a Subject and an Observable?


If you have used RxJs you will have encountered the Observable; the quintessential core element of the library. You may also have encountered the concept of Subjects and may be wondering how they differ from observables. While there are commonalities between Subject and Observable they are not exactly the same thing. Subjects provide some additional functionality and can be used for specific purposes where Observable may not be the best solution or even a viable solution.

What is an Observable?

First off, let's define what an observable is. An object represents some information at some moment in time. An array represents a set of information at some moment in time. What time, however, is not an intrinsic aspect of an object or an array.


An observable represents a stream of events or information that occur, or arrive, over time. Observables bring the time aspect into the fold and deliver information at specific times. You know that at the moment in time you receive a notification from an observable stream the information exposed by that notification is correct for that moment in time (i.e. for application state or for an error that just occurred, etc.)


Observables represent streams of information over time.

Push vs. Pull

The official documentation on Observables describes them as follows:


"Observables are lazy Push collections of multiple values."

Single

Multiple

Pull

Function

Iterator

Push

Promise

Observable

A function (a producer) is a "pull" type facility, as it does not know when it will be called, it simply produces a result when it is called. The consumer of the function decides when to call a function, provide any input and consume its return value. Consumers can "pull" results from functions.


An observable (also a producer), on the other hand, is a "push" type facility as the observable will produce values on its own schedule over time. The consumer of an observable waits until values are produced, handles the values as they arrive but does not know ahead of time when any value will arrive. Producers can "push" results through observables.

Multi-Channel

Every observable is a "multi-channel" facility, in a sense. There is a "channel" for normal values, a "channel" for an error if one occurs and a "channel" for reporting completion. In the most basic sense, subscribing to an observable allows you to provide an Observer or, more specifically, a partial one:

An Observer is an object that exposes three methods: next(value: T), error(any) and complete(). Subscribing will bind these methods to each type of notification, or each "channel", of the observable.

Range

Side Effect

Next

0..∞

Error

0..1

Stops Stream

Complete

0..1

Stops Stream

Error and completion channels have a range of zero or one occurrence, whereas, the normal value channel or "next" channel has a range of zero to infinity. Streams may complete, may error but some streams may continue to emit values indefinitely and never stop. Further, some streams may never emit anything.

Subscribable Interface

Every Observable there is also a Subscribable. The primary means by which values from observables can be observed is through subscribing to the stream of information they represent. The Subscribable interface exposes a single method:

Subscribing returns an Unsubscribable; which simply provides an interface to allow consumers of streams to unsubscribe and stop receiving information from the stream:

Core Observable Interface

Every Observable in RxJs, or ones you create yourself, expose a specific public interface that can be used to interact with that observable. In addition to the Subscribable interface above every observable exposes a pipe() method (allows augmentation of the stream with operators), as well as a couple of other often infrequently-used methods:

Creating Observables

Observables MAY be created from your own producers in order to expose an observable stream for the information those producers manage. Note that Observable is generic. The type T represents the type of the information this Observable will stream.


When creating an observable, you pass in a callback function that accepts a Subscriber which is also an Observer. Subscribers therefore must expose the three key observer methods described previously.


Observables, in concert with Subscribers, can exhibit subject-like behavior in that they expose a stream and allow a producer to control emissions on that stream. Such a construct may look like this:

Creating an observable in this manner is a bit convoluted and may be a bit confusing. The subscriber is actually a facility that can be used to emit notifications onto the stream your new observable represents; so it is not exactly subscribing. It is more of a tool to tell potential subscribers what is happening with your observable.


It ends up being easier, and with less confusing nomenclature, to use a Subject which encapsulates all of this functionality in an easier to use interface. Further, the very term is clear about what it represents: the subject of observation.

What is a Subject?

A subject is an intrinsically richer facility than an observable. Where an Observable simply represents a stream of information over time a Subject gives you easy control over emitting notifications into a stream and allows you to expose that stream as an Observable. Subjects can be thought of like event emitters. Note that while observables themselves are often thought of as event emitters they are not actually a source of events themselves; whereas subjects are.


A basic Subject, which is a first-class type included with RxJs, is an extension of the Observable type. Therefore, subjects ARE observables but they are also MORE than an observable. In addition to the core observable functionality, subjects also expose three key methods: next(), error(err: any) and complete().

Subjects are also subscription-like in that they expose an unsubscribe() method that can be used to unsubscribe all existing observers and close the stream. This is roughly the same as calling complete(). Subjects also expose an asObservable() method that can be used to create a new Observable for the subject.


Like Observable, a Subject is generic and the type represents the type of information the subject streams.

Nextable

The main reason to create a Subject is to explicitly produce values. The most commonly used method on a subject is next(value: T). Whenever your producer, which is your own code that will usually compose a subject, needs to produce a value it simply needs to call subject.next(value).

Errorable

When your producer has encountered some error in time it can notify its consumers (subscribers) that the error has occurred. Errors are stream-ending events and when you notify your consumers that an error has occurred you are also implicitly ending the stream.

Completable

Producers may also support completion. Completion is an optional aspect of observable streams that allows consumers, as well as any operator pipelines bound to the stream, to clean themselves up and unsubscribe. If a producer is only capable of producing a finite number of values, when it has completed its work, it may also complete the Subject which will complete the underlying stream.

Enhanced Subjects

Where subjects truly begin to differentiate themselves from observables is in the way they can be extended and enhanced with intrinsic, reusable capabilities. While the basic nature of a subject can be replicated when creating a new Observable(), and utilizing its Subscriber to control the emission of values, extending Subject is a much easier way to include additional functionality.


The RxJS library exposes a number of different types of subjects all of which may be used as the basis for your own types of subjects that expose even more unique capabilities.

BehaviorSubject

The first and often most commonly used Subject subclass in RxJs is the BehaviorSubject. This type of subject represents "a value that changes over time". While all observables represent information over time a behavior subject is a type of subject that keeps track of the last value that it emitted. This value is then emitted again for any new subscriber after that last emission. Any subsequent values are emitted to all subscribers and, again, remembered by the behavior.


Being able to keep track of the last value emitted so that "late" subscribers may also receive them is often a very important trait. Sometimes the exact moment of emission is not an important factor and, with an asynchronous programming environment, the exact order of execution is not necessarily guaranteed. BehaviorSubject is an excellent tool to ensure that within an asynchronous environment that late subscribers to streams from your providers are able to get the latest value, regardless of when they subscribe.

Always Has a Value

When constructing a new BehaviorSubject you must provide an initial value. Behaviors by definition are a value that changes over time therefore there must be some kind of initial value, even if it is null.

Exposes Its Value

A BehaviorSubject also makes its value publicly available. The value is always accessible via either the .value property or the getValue() method. These are non-reactive ways of getting ahold of the value so they can be used in any kind of code if necessary.

ReplaySubject

Another commonly used Subject subclass in RxJs is the ReplaySubject. This type of subject is similar to BehaviorSubject in that it has a memory, however, it differs in that it is not actually a behavior in the sense of remembering "a value" over time. It remembers everything that it has emitted or up to a configurable limit of events.


Where a behavior can only notify late subscribers of the most recent value a replay can notify late subscribers of everything that happened before they subscribed. In some cases, this may be critical to ensure the proper behavior of your consumers.

Limiting Replay's Memory

Take note, however, that unless otherwise configured a replay will remember EVERY event it emits! This means it will continue to consume ever more memory over time, which is a potential drawback.


Thankfully, the ReplaySubject allows you to define either or both a buffer size and a window time. The bufferSize limits the absolute number of events the replay can remember while the windowTime limits how long an event can be remembered. They both default to Infinity, however, either one or the other or both may be configured to limit how many events your replay remembers thus constraining its long-term memory usage.

AsyncSubject

The last, and also least commonly used Subject subclass in RxJs is the AsyncSubject. This type of subject is unique in that it captures the most recent value that has been nexted into the subject but only emits a value to its observers once the subject has also been completed.


This kind of subject can be useful for "once and done" providers that need to perform some kind of asynchronous operation once, after which they are done, completed. This is a less common scenario but useful enough that RxJs exposes a ready-made subject for this kind of behavior.

Custom Subjects

It is possible to create your own custom subjects. Implementing them is fairly easy and you can often piggy-back your implementation on top of existing RxJs subjects. As a simple case study, say you wanted an AverageSubject that maintained the average of all numbers submitted to it so that each new subscriber would get the most recent average. Further, this subject would emit the average of all the numbers that were passed to next() rather than emitting those numbers themselves. This is similar to a BehaviorSubject; in fact it is a behavior, however, but it is a more specific case.


We can extend BehaviorSubject<number> and override the next method to help us keep track of our sum and count to maintain the average as well as emit the average rather than the supplied number.

Note that the actual average itself is tracked as the latest value of the underlying BehaviorSubject so it does not need to be tracked by our subclass. We simply need to track the sum and count and compute a new average as the new value that we pass to the underlying behavior each time next is called.

Conclusion

Well there you have it! Observables are the core concept within RxJs that represents the fundamental primitive that makes all of its wonderful reactivity work: streams of data over time. Subjects, on the other hand, are tools to create observables and feed data into those streams. Subjects "are observable", however, observables are not subjects themselves.


Subjects are providers. Observables are the bridge between providers and consumers. Subjects also provide a very easy way to create new types of providers, even ones that may inherently transform the information fed into them, such as our example AverageSubject.

Need Support With a Project?

Start experiencing the peace and security your team needs, and continue getting the recognition you deserve. Connect with us below. 

First Name* Required field!
Last Name* Required field!
Job Title* Required field!
Business Email* Required field!
Phone Required field!
Tell us about your project Required field!
View Details
- +
Sold Out