To master Angular, you must stop thinking about isolated 'events' and start thinking about continuous 'streams' of data.
1Eager vs. Lazy
When you create a Promise, the work starts immediately. If you're fetching data, the request goes out the moment the code runs. Observables, however, are blueprints. They define 'how' data should be handled, but they don't 'do' anything until a consumer calls .subscribe(). This laziness allows Angular to be incredibly efficient, only processing data when there's an active observer.
2Single vs. Multiple
A Promise is a guarantee of a single resolution: it either succeeds or fails once. An Observable is a stream. It can emit a value, wait three seconds, emit another value, and then eventually complete. This makes Observables ideal for things like handling user clicks, real-time web sockets, or search inputs where the value changes multiple times.
3Step-by-Step Breakdown
Async programming is how we handle events that happen in the future. In JavaScript, we usually start with Promises.
A Promise is like a pager. It rings once when your food is ready. It handles one event, then it's done.
But Angular uses 'Observables'. An Observable is like a conveyor belt. It can deliver zero, one, or many items over time.
Checkpoint: Which async pattern in Angular can emit multiple values over time?
- βPromise
- βObservable
Promises are 'Eager'βthey start immediately. Observables are 'Lazy'βnothing happens until someone 'subscribes' to the stream.
This laziness is powerful! You can define complex logic without actually executing it until the data is really needed.
Checkpoint: True or False: An Observable will start emitting data even if no one has called .subscribe() on it.
- βTrue
- βFalse
You've unlocked the reactive mindset! Thinking in streams is the first step to mastering Angular's data flow.
Next, we'll learn how to create and manage these streams manually.
Level Up π
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1A Stream-Driven UI Update Still Needs an Announcement Mechanism
Whether data arrives via a Promise or an Observable, the resulting UI change (new content appearing, a list updating) needs the exact same accessibility treatment β an `aria-live` region or explicit focus management β since the underlying async mechanism is invisible to the end user entirely.
2Cancellable Observable Streams Can Prevent a Specific Accessibility Bug: Stale Announcements
Because Observables (unlike Promises) can be unsubscribed, a component that's destroyed mid-request can cleanly cancel it β preventing a since-navigated-away announcement or focus change from firing for a view the user can no longer see.
SEO Implications
- 1
Neither Promises nor Observables Have Direct SEO Weight β Both Execute Purely Client-Side
The choice between async patterns is an internal implementation detail invisible to search engines; what matters for SEO is whether the eventual resolved data gets rendered into HTML during a server-side render pass, regardless of which async primitive fetched it.
- 2
Cancellable Requests (a Unique Observable Capability) Can Reduce Wasted Server Load
An Observable-based search-as-you-type feature can cancel a stale in-flight request the instant a new keystroke arrives β a Promise-based equivalent can't be canceled once started, potentially wasting server resources on requests whose results will be discarded anyway.
Best Practices
Use Promises (via `async`/`await`) for Simple, One-Time Async Operations
A one-off operation like reading a single value once has less conceptual overhead as a Promise β reaching for full RxJS Observable machinery for something that will only ever emit once and can't be canceled is often unnecessary complexity.
Use Observables When You Need Cancellation, Multiple Emissions, or Operator Composition
Anything involving a stream of values over time (user input, WebSocket messages), the ability to cancel an in-flight operation, or composing multiple async operations together (via operators like `switchMap`) is where Observables provide capabilities Promises fundamentally lack.
Frequent Bugs
Rapidly firing a search-as-you-type feature causes results from an earlier, slower keystroke to overwrite results from a more recent one.
This is exactly the class of race-condition bug Observables (specifically the `switchMap` operator) exist to solve β `switchMap` automatically cancels the previous inner Observable when a new value arrives, ensuring only the latest request's result is ever used. A naive Promise-based implementation has no equivalent built-in cancellation.
Code awaiting a Promise inside a component never resolves after the user navigates away and back.
Promises can't be canceled once started β if the component is destroyed before the Promise resolves, the `.then()` callback can still fire later and attempt to update a component that no longer exists. An Observable-based equivalent, properly unsubscribed in `ngOnDestroy` (or via the async pipe), avoids this because unsubscribing genuinely stops the pending work from affecting the destroyed component.
Real-World Examples
Search-as-You-Type With Automatic Request Cancellation
A live search feature uses RxJS operators to debounce keystrokes and cancel any in-flight request when a newer one starts, a capability a Promise-based implementation couldn't provide without significant manual bookkeeping.
searchTerm$.pipe(
debounceTime(300),
switchMap(term => this.http.get(`/api/search?q=${term}`))
).subscribe(results => this.results = results);