Understanding the Difference Between Observer and Subscriber in RxJS

April 7, 2025 7:53 PM

RXJS Observer RXJS Subscriber
post image

When working with RxJS in Angular, you often encounter the terms Observer and Subscriber. While they are closely related, they serve different purposes in the context of observables. This article will help you understand the difference between the two and clarify why the observer in the new Observable() constructor is typed as Subscriber.

image_11.png

What is an Observer?

An Observer is an object that defines how to handle the values, errors, and completion notifications emitted by an observable. It has three main methods:

  1. next(value): Handles the emitted value.
  2. error(err): Handles any error emitted by the observable.
  3. complete(): Handles the completion of the observable.

Example of an Observer:

The observer is passed to the subscribe() method of an observable to listen for emissions.

What is a Subscriber?

A Subscriber is an advanced version of an Observer. It extends the Observer interface and adds additional functionality, such as managing the subscription lifecycle. When you create an observable using new Observable(), the observer parameter inside the constructor is actually a Subscriber.

Why is it a Subscriber?

The Subscriber provides:

  1. Observer Methods: It has next, error, and complete methods, just like an Observer.
  2. Subscription Management: It includes methods like unsubscribe() to manage the lifecycle of the subscription.
  3. Internal Handling: RxJS uses the Subscriber internally to ensure safe emissions and manage cleanup


Key Difference Between Observer and Subscriber

FeatureObserverSubscriber
DefinitionDefines how to handle observable emissions.Extends Observer and manages subscriptions.
Methodsnext, error, complete.Includes next, error, complete, and unsubscribe.
UsagePassed to subscribe() to listen for emissions.Used internally by RxJS to manage observable behavior.
In new Observable()Not directly used.The observer parameter is actually a Subscriber.

Why is the observer in new Observable() Typed as Subscriber?

When you create an observable using new Observable(), the function you pass to the constructor receives a Subscriber object. This is because RxJS internally wraps the Observer in a Subscriber to provide additional functionality, such as managing the subscription lifecycle.

In this example:

  • The observer parameter is typed as Subscriber<string>.
  • You can use it like an Observer (e.g., call next, error, or complete), but it also has additional methods like unsubscribe.


Implementing the async validator

In your SignupComponent, you have the forbiddenEmails method, which creates a custom observable for asynchronous validation. Here’s how the observer (typed as Subscriber) works in this context:

forbiddenEmails = (control: AbstractControl): Observable<{ isForbidden: boolean }> => {
  return new Observable((observer: Subscriber<{isForbidden: boolean}>) => {
    const forbiddenList = ['test@example.com', 'admin@example.com'];
    const value = control.value;


    setTimeout(() => {
      if (forbiddenList.includes(value)) {
        observer.next({ isForbidden: true }); // Emit validation error
      } else {
        observer.next({ isForbidden: false }); // Emit no error
      }
      observer.complete(); // Complete the observable
    }, 1000); // Simulate async delay
  });
};


How It Works:

  1. The observer parameter is a Subscriber<{ isForbidden: boolean }> object.
  2. It emits validation results using observer.next().
  3. It signals the completion of the observable using observer.complete()


Overall summary:

  • Observer: Defines how to handle values, errors, and completion notifications from an observable.
  • Subscriber: Extends Observer and adds subscription management. It is used internally by RxJS.
  • In the new Observable() constructor, the observer parameter is actually a Subscriber, which provides additional functionality beyond a plain Observer.

Creating a Plain Observable

Here’s a simple example of creating and using a plain Observable

import { Observable } from 'rxjs';


const plainObservable = new Observable<string>((observer) => {
  // Emit a value
  observer.next('Hello');


  // Emit another value
  observer.next('World');


  // Complete the observable
  observer.complete();


  // Emit after completion (this won't be executed)
  observer.next('This will not be logged');
});


// Subscribe to the observable
plainObservable.subscribe({
  next: (value) => console.log(value), // Logs emitted values
  error: (err) => console.error(err), // Logs errors
  complete: () => console.log('Observable completed'), // Logs when completed
});


  1. Creating the Observable:

    • The new Observable() constructor takes a function with an observer parameter.
    • The observer object has three methods:
      • next(value): Emits a value to the subscriber.
      • error(err): Emits an error and terminates the observable.
      • complete(): Signals that the observable has completed.
  2. Subscribing to the Observable:

    • Use the subscribe() method to listen to the observable.
    • Pass an object with next, error, and complete callbacks to handle emitted values, errors, and completion

Comments


    Read next