Skip to the solution
MediumFrontend9 min read

What is the difference between Observables and Promises?

524 views

The problem

Question presented to candidate: "Angular's HttpClient returns an Observable, while fetch returns a Promise. What is actually different between the two, and why did Angular choose Observables?"

What a strong answer should cover:

  • Eager vs lazy: a Promise starts its work when it is created; an Observable does nothing until it is subscribed, and runs again for every subscriber (cold).
  • One value vs many: a Promise settles once (later resolve calls are ignored); an Observable can emit zero, one or many values, then complete or error.
  • Timing: then callbacks are always asynchronous (microtasks); an Observable can emit synchronously during subscribe().
  • Cancellation: unsubscribing runs the producer's teardown (clears timers, aborts requests); a Promise cannot be cancelled.
  • Operators: RxJS gives map, switchMap, retry, debounceTime, combination; Promises have then, Promise.all/race/allSettled/any.
  • Conversion: from(promise), defer(() => promise) for laziness, firstValueFrom/lastValueFrom back (with EmptyError on an empty stream).

Clarifying questions expected:

  • "Do you want the conceptual comparison, or how it affects HttpClient code in components?"
  • "Is the team mixing async/await with Observables today?"

Code / implementation expected: Optional β€” a small snippet showing eager vs lazy execution and cancelling a stream.

  • rxjs
  • observables

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

9 min read Β· 10 sections

Read the code

AngularEager vs lazy, one value vs many, and cancelling a stream
import { Component, signal } from "@angular/core";
import { Observable, Subscription, firstValueFrom, from } from "rxjs";

@Component({
  selector: "app-root",
  template: `
    <button (click)="createBoth()">1. Create both</button>
    <button (click)="consumeBoth()">2. Subscribe / then</button>
    <button (click)="startStream()">3. Start ticking stream</button>
    <button (click)="cancel()">4. Cancel stream</button>
    <button (click)="convert()">5. Promise to Observable to Promise</button>
    <ol>@for (line of log(); track $index) { <li>{{ line }}</li> }</ol>
  `,
})
export class AppComponent {
  log = signal<string[]>([]);
  private promise?: Promise<string>;
  private observable?: Observable<string>;
  private sub?: Subscription;

  private write(line: string) { this.log.update((l) => [...l, line]); }

  createBoth() {
    // A Promise starts its work the moment it is created (eager).
    this.promise = new Promise((resolve) => { this.write("promise: executor ran"); resolve("P"); });
    // An Observable is only a recipe until someone subscribes (lazy).
    this.observable = new Observable((sub) => {
      this.write("observable: producer ran");
      sub.next("O1"); sub.next("O2"); sub.complete(); // many values, then done
    });
    this.write("both created");
  }

  consumeBoth() {
    this.promise?.then((v) => this.write(`then -> ${v} (always async)`));
    this.observable?.subscribe((v) => this.write(`subscribe -> ${v} (sync here)`));
    this.write("end of click handler");
  }

  startStream() {
    const ticks = new Observable<number>((sub) => {
      let n = 0;
      const id = setInterval(() => sub.next(++n), 100);
      return () => { clearInterval(id); this.write("teardown: interval cleared"); };
    });
    this.sub = ticks.subscribe((n) => this.write(`tick ${n}`));
  }

  cancel() { this.sub?.unsubscribe(); }

  // Converting: from() wraps a Promise, firstValueFrom() turns an Observable back into one.
  async convert() {
    const first = await firstValueFrom(from(Promise.resolve(42)));
    this.write(`firstValueFrom(from(promise)) = ${first}`);
  }
}

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 52 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 nextMedium

What are ng-container and ng-template?

Continue