Create your own
Lesson illustration

Observables vs. Promises: Core Concepts

Hello! Welcome to your first lesson on RxJS.

Given your goal to master RxJS for advanced front-end development, our first step is to build a rock-solid understanding of its fundamental building block: the Observable.

This lesson is designed to help you analyze the core contract of an Observable. We will break down its three key characteristics: the producer-consumer relationship, its lazy execution model, and its built-in mechanism for teardown logic. We will then contrast this directly with Promises, a concept you are undoubtedly familiar with, to highlight what makes Observables uniquely powerful for managing asynchronous events and data streams.

Let's begin.

1. The Core Components: Producer, Consumer, and Subscription

At its heart, the relationship in RxJS is simple. You have something that produces values (the Observable), something that consumes or listens for those values (the Observer), and a connection between them (the Subscription).

  • Observable (The Producer): Think of this as a blueprint or a recipe for producing a sequence of values over time. It doesn't do anything by itself; it just defines where the values will come from (e.g., user clicks, an HTTP request, a timer).
  • Observer (The Consumer): This is an object containing up to three callback functions:
    • next(value): Called for each value the Observable delivers.
    • error(err): Called if the Observable fails. This terminates the stream.
    • complete(): Called when the Observable has no more values to send. This also terminates the stream.
  • Subscription (The Connection): When you call .subscribe() on an Observable and pass it an Observer, you create a Subscription. This action "activates" the Observable, causing it to start producing values. The Subscription object represents this active connection and is the key to canceling it.

To see these three parts in action, let's watch a short segment from a tutorial by Academind.

OBSERVABLES, OBSERVERS & SUBSCRIPTIONS | RxJS TUTORIAL

This video provides a clear, visual introduction to the roles of Observables, Observers, and Subscriptions.

Watch the first 2 minutes and 41 seconds. Focus on how the narrator defines the three main components and the 'contract' they form.

2. The Observable Contract

Now that we have the basic vocabulary, let's analyze the rules that govern how these parts interact. This is often called the "Observable contract."

Lazy Execution

One of the most significant differences between an Observable and a Promise is when the underlying work begins.

  • Promises are eager: The moment you create a new Promise (new Promise(...)), the function inside it executes immediately.
  • Observables are lazy: The function passed to the new Observable(...) constructor does not execute until an Observer subscribes to it.

This makes Observables highly efficient. You can define complex data streams, but no computation or resource allocation happens until something is actually ready to consume the values. In this way, an Observable is much more like a function definition, which does nothing until it is called.

The official RxJS documentation explains this "pull vs. push" distinction well.

Observable

Let's read a section from the official RxJS documentation titled 'Observable'. It provides a precise definition of pull vs. push systems and makes an excellent analogy between Observables and functions.

Read the sections 'Pull versus Push' and 'Observables as generalizations of functions'. Pay close attention to the code examples that show how subscribing to an Observable is analogous to calling a function.

To see a practical demonstration of lazy vs. eager execution, this next video provides a side-by-side comparison.

Observable vs Promise: Understanding the Differences for Interviews | Angular Interview Concepts

This video from Web Tech Talk directly contrasts the execution models of Observables and Promises with a simple code example.

Watch from 01:35 to 03:22. Notice when the console.log from inside the Promise constructor appears versus the one from the Observable constructor.

The Observable Grammar: A Predictable Lifecycle

An Observable execution follows a strict set of rules, often expressed as a regular expression: next*(error|complete)?.

This means:

  1. An Observable can emit zero or more next notifications.
  2. An Observable can, at most, send one terminating notification, which is either error or complete.
  3. Once error or complete is called, the execution is over, and no further notifications will be delivered.

This contract provides a predictable lifecycle, which is essential for managing streams reliably.

The official documentation covers this contract clearly.

Observable

Let's return to the RxJS documentation to formalize our understanding of the Observable's execution and its grammar.

Read the section 'Executing Observables'. Focus on the three notification types and the explanation of the 'Observable Grammar'.

Teardown Logic: Preventing Memory Leaks

Since Observables can model infinite streams (like DOM events or WebSocket connections), it's critical to have a way to stop listening and clean up any resources the Observable may have allocated (e.g., event listeners, timers, open sockets). Without proper cleanup, you would introduce memory leaks into your application.

This is the purpose of teardown logic.

When you create an Observable, the function you provide to the constructor can optionally return another function. This returned function is the teardown logic. It is executed automatically in two scenarios:

  1. The Observable sends a complete or error notification.
  2. The consumer manually unsubscribes from the Observable.

The .subscribe() method returns a Subscription object, which has an unsubscribe() method. Calling this method triggers the teardown logic and stops the flow of values to that specific Observer.

Let's watch the final part of the Academind video, which demonstrates this concept perfectly.

OBSERVABLES, OBSERVERS & SUBSCRIPTIONS | RxJS TUTORIAL

This segment shows how to implement teardown logic by returning a function from the Observable constructor and how to manually trigger it by calling unsubscribe().

Watch from 15:05 to 17:16. Pay close attention to how subscription.unsubscribe() is used to stop an infinite stream and why this is crucial for preventing memory leaks.

Ben Lesh, the lead of the RxJS project, provides a powerful mental model for this: "An Observable is just a function that takes an observer and returns a function (the teardown logic)." This functional perspective strips away the "magic" and is a very useful way to think about it.

Learning Observable By Building Observable

This article, 'Learning Observable By Building Observable' by Ben Lesh, provides a fundamental perspective on what an Observable is. It's a great way to solidify your mental model.

Read the first section, 'Observable is just a function...', and the final section, 'TLDR:'. This reinforces the core idea of an Observable as a function that sets up a producer-consumer connection and provides a way to tear it down.

3. Observable vs. Promise: A Summary

We've touched on the differences throughout the lesson. Let's consolidate them into a clear comparison. Understanding these distinctions is key to knowing when to use each tool.

FeaturePromiseObservable
ExecutionEager. Executes immediately upon creation.Lazy. Executes only when subscribe() is called.
ValuesEmits a single value (or a single rejection).Emits multiple values over time.
CancellabilityNo. Once initiated, a Promise cannot be cancelled.Yes. A subscription can be cancelled via unsubscribe().
DeliveryAlways asynchronous. The .then() callback is always deferred.Can be synchronous or asynchronous, depending on the producer's implementation.

To see these differences demonstrated with code, let's watch the remaining relevant parts of the "Observable vs Promise" video.

Observable vs Promise: Understanding the Differences for Interviews | Angular Interview Concepts

This video clearly demonstrates the differences in value emission, cancellability, and synchronous/asynchronous behavior.

Watch the segments from 03:22 to 07:42. They cover how Observables handle multiple values, how they can be cancelled, and how they can operate both synchronously and asynchronously.

Conclusion

In this lesson, we have established the foundational mental model for RxJS.

Key Takeaways:

  • An Observable is a lazy producer of values, a blueprint for a data stream.
  • An Observer is a consumer with next, error, and complete handlers.
  • A Subscription is the active connection created by calling subscribe(), which starts the execution and allows for cancellation.
  • The Observable contract is next*(error|complete)?, ensuring a predictable lifecycle.
  • Teardown logic (the function returned from the constructor) is crucial for resource management and preventing memory leaks.
  • Compared to Promises, Observables are lazy, can handle multiple values, and are cancellable.

This core contract is the bedrock upon which all of RxJS is built. A firm grasp of these principles will make understanding the more complex operators and patterns much more intuitive.

In our next lesson, we will put this theory into practice by learning how to create Observables from common sources like static data, DOM events, and Promises using RxJS's powerful creation functions: of, from, and fromEvent.

Can't find a good explanation? Sign up and we'll make it for you

Sign up