Skip to content

Cold Observables

A Cold Observable is one where the data producer (the logic inside the Observable) doesn't start running or emitting values until you subscribe to it.

Crucially, each time you subscribe to a cold Observable, it starts its work from the very beginning and generates a fresh, independent sequence of values just for that subscriber.

Key Characteristics#

  1. Lazy Execution: The code that produces values only runs when subscribe() is called. No subscription = no execution.
  2. Independent Execution per Subscriber: Every subscriber gets their own private stream of data. What happens in one subscription doesn't affect another.

Real-World Analogy#

  1. Watching a YouTube Video (On-Demand):

    • When you click "Play" on a video (you subscribe), the video stream starts playing from the beginning just for you.
    • If your friend clicks "Play" on the same video later (another subscription), they also get the video starting from the beginning, completely independent of your playback.
    • The YouTube server (the Observable) delivers a separate, unique stream to each viewer (each subscriber).
  2. Playing a DVD or Blu-ray:

    • Putting the disc in the player and pressing play (subscribing) starts the movie from the beginning.
    • Every time someone does this with their own player (another subscription), the movie starts fresh for them.

Examples in Angular/RxJS#

  1. HttpClient (Very Common):

    • Observables returned by Angular's HttpClient (e.g., http.get(), http.post()) are cold.
    • Every time you subscribe() to dataService.getItems(), Angular makes a new HTTP request to the server.
    • If Component A subscribes and Component B subscribes to the same service call, two separate network requests will be made.
    // In some component:
    ngOnInit() {
      console.log("Subscribing first time to getItems...");
      this.dataService.getItems().subscribe(data => {
        console.log("First subscription received data.");
      });
    
      // Some time later, maybe in response to a user action
      console.log("Subscribing second time to getItems...");
      this.dataService.getItems().subscribe(data => {
        console.log("Second subscription received data."); // This triggers a NEW HTTP request
      });
    }
    
  2. Basic Creation Functions: Many RxJS creation functions like of(), from(), range(), timer(), interval() typically create cold Observables.

    import { interval } from "rxjs";
    
    // interval(1000) emits 0, 1, 2... every second
    const coldInterval = interval(1000);
    
    console.log("Subscribing A");
    const subA = coldInterval.subscribe((val) => console.log(`Sub A: ${val}`)); // Starts a timer for A
    
    setTimeout(() => {
      console.log("Subscribing B");
      const subB = coldInterval.subscribe((val) =>
        console.log(`Sub B: ${val}`)
      ); // Starts a NEW timer for B
    }, 3000);
    
    // Output will show:
    // Subscribing A
    // Sub A: 0 (at 1s)
    // Sub A: 1 (at 2s)
    // Sub A: 2 (at 3s)
    // Subscribing B
    // Sub B: 0 (at 4s, because B's timer started at 3s)
    // Sub A: 3 (at 4s)
    // Sub B: 1 (at 5s)
    // Sub A: 4 (at 5s)
    // ... and so on. A and B have independent timers.
    

Summary#

Think of Cold Observables as blueprints or recipes for generating data streams. Each time you ask for the stream (by subscribing), the recipe is followed from the start, creating a unique instance just for you. Most Observables you deal with for one-off tasks like API calls are cold.