Skip to the solution
HardFrontend11 min read

What is the difference between Subject, BehaviorSubject, and ReplaySubject?

350 views

The problem

Question presented to candidate: "We keep the logged-in user in a service and several components subscribe to it, some of them long after login. Which kind of Subject would you use, and how do Subject, BehaviorSubject and ReplaySubject differ?"

What a strong answer should cover:

  • A Subject is both an Observable and an Observer: it multicasts each next() to every current subscriber, and is hot (values sent before you subscribe are gone).
  • The three differ in what a late subscriber receives: Subject gives nothing from the past, BehaviorSubject gives the current value (it needs an initial one), ReplaySubject(n) replays the last n values (optionally limited by a time window).
  • BehaviorSubject exposes a synchronous getValue() / value; ReplaySubject has no initial value and no getter.
  • After complete() a late subscriber of a BehaviorSubject gets only the completion, while a ReplaySubject still replays its buffer.
  • Expose subjects with asObservable() so only the owning service can call next(); in modern Angular a signal() often replaces a BehaviorSubject for UI state.
  • Mention AsyncSubject (emits only the last value, on complete) as the fourth variant.

Clarifying questions expected:

  • "Does a component that subscribes later need the current value, or only future changes?"
  • "Is this UI state the template reads (a signal might fit better) or an event stream?"

Code / implementation expected: Yes β€” a small service or component that shows what a late subscriber gets from each subject.

  • rxjs
  • subject

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

11 min read Β· 10 sections

Read the code

AngularLate subscriber: what Subject, BehaviorSubject(0) and ReplaySubject(2) hand over
import { Component, OnDestroy, signal } from "@angular/core";
import { BehaviorSubject, ReplaySubject, Subject, Subscription } from "rxjs";

// Three kinds of Subject receive the same values. A "late" subscriber joins
// after two values have already been sent, so you can see what each one replays.
@Component({
  selector: "app-root",
  template: `
    <button (click)="emit()">next({{ counter() + 1 }})</button>
    <button (click)="addLate()" [disabled]="lateAdded()">Add late subscriber</button>
    <ul>
      <li>Subject: {{ logs.subject().join(", ") || "-" }}</li>
      <li>BehaviorSubject(0): {{ logs.behavior().join(", ") || "-" }}</li>
      <li>ReplaySubject(2): {{ logs.replay().join(", ") || "-" }}</li>
    </ul>
    <p>Current BehaviorSubject value: {{ current() }}</p>
  `,
})
export class AppComponent implements OnDestroy {
  private subject = new Subject<number>();
  private behavior = new BehaviorSubject<number>(0);
  private replay = new ReplaySubject<number>(2);
  private subs = new Subscription();

  counter = signal(0);
  lateAdded = signal(false);
  current = signal(this.behavior.getValue());
  // What the LATE subscriber has received from each subject.
  logs = { subject: signal<string[]>([]), behavior: signal<string[]>([]), replay: signal<string[]>([]) };

  emit() {
    const n = this.counter() + 1;
    this.counter.set(n);
    this.subject.next(n);
    this.behavior.next(n);
    this.replay.next(n);
    this.current.set(this.behavior.value);
  }

  addLate() {
    this.lateAdded.set(true);
    const track = (key: "subject" | "behavior" | "replay") => (v: number) =>
      this.logs[key].update((l) => [...l, "got " + v]);
    this.subs.add(this.subject.subscribe(track("subject")));
    this.subs.add(this.behavior.subscribe(track("behavior")));
    this.subs.add(this.replay.subscribe(track("replay")));
  }

  ngOnDestroy() {
    this.subs.unsubscribe();
  }
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 110 of 121 in Angular

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Angular questions
Up nextHard

Why use Renderer2 instead of direct DOM access?

Continue