Difference between Observable and Promise | with examples
Promises and Observables are two ways to handle asynchronous programming in JavaScript, with each offering unique features and benefits. While Observables can mimic all the capabilities of Promises, they also provide additional flexibility and functionality that Promises do not.
Key Takeaways
- Promises resolve once and emit a single result; Observables can emit multiple values over time.
- Promises automatically start execution when created, while Observables only execute upon subscription.
- Observables are part of the RxJS library, offering powerful operators for data processing that Promises lack.
- Observables offer cancellable flows, which is not possible with Promises.
What is a Promise?
A Promise in JavaScript offers a streamlined approach to handling asynchronous operations. Native since ES6, Promises allow you to work with asynchronous code without the nested pyramid of callbacks.
Example of a Promise:
let promise = new Promise((resolve) => {
setTimeout(() => {
resolve("some value");
}, 1000);
});
promise.then(value => {
console.log(value);
});
Output
some value
A Promise executes immediately, running any asynchronous code and eventually calls resolve or reject to determine the outcome. The then() method is used to handle the resolved value.
What is an Observable?
Observables, implemented via the RxJS library, adopt the observer design pattern to manage asynchronous data streams. Unlike Promises, Observables offer more dynamic capabilities with regards to data emission and manipulation.
Example of an Observable:
import { Observable } from 'rxjs';
let observable = new Observable((observer) => {
setTimeout(() => {
observer.next("some value");
}, 1000);
});
observable.subscribe(value => {
console.log(value);
});
Output
some value
Observables in JavaScript must be imported from the RxJS library. Unlike Promises, Observables don’t start execution until you call subscribe().
Difference Between Observables and Promises:
Single vs Multiple Values
Promises resolve a single value:
let promise = new Promise((resolve) => {
resolve("a");
resolve("b");
});
promise.then(value => console.log(value));
Output
a
Observables can emit multiple values over time:
let observable = new Observable((observer) => {
observer.next("a");
observer.next("b");
});
observable.subscribe(value => {
console.log(value);
});
Output
a
b
Observables can emit multiple values and each call to next() pushes a new value to subscribers.
Eager vs Lazy Execution
Promises start execution immediately:
let promise = new Promise((resolve) => {
console.log("promise is running");
resolve("a");
});
console.log("start");
promise.then(value => console.log(value));
console.log("end");
Output
promise is running
start
end
a
Observables execute only when subscribed:
let observable = new Observable((observer) => {
console.log("observable is running");
observer.next("a");
});
console.log("start");
observable.subscribe(value => console.log(value));
console.log("end");
Output
start
observable is running
a
end
For Observables, since execution is lazy, code within the Observable block only runs when Subscribe is invoked.
Cancellable
Promises can't be canceled once started, while Observables can be canceled using the unsubscribe() method:
let observable = new Observable((observer) => {
setTimeout(() => {
console.log("calling next");
observer.next("a");
}, 1000);
});
const subscription = observable.subscribe(value => console.log(value));
subscription.unsubscribe();
Output
calling next
By using unsubscribe(), you prevent the continuation or repetition of data emission, effectively canceling the Observable.
Unicast vs Multicast
Promises are unicast:
let promise = new Promise((resolve) => {
resolve(Math.random());
});
promise.then(value => console.log(value));
promise.then(value => console.log(value));
Output
0.768598539600432
Observables are multicast:
let observable = new Observable((observer) => {
observer.next(Math.random());
});
observable.subscribe(value => console.log(value));
observable.subscribe(value => console.log(value));
Output
0.6964325798899575
0.5931491554914805
Observables execute anew for each subscription, whereas Promises deliver the result of a single execution to all subscribers.
Sync vs Async Handlers
Promises have asynchronous handlers:
let promise = new Promise((resolve) => {
resolve("promise is resolving");
});
console.log("START");
promise.then(value => console.log(value));
console.log("END");
Output
START
END
promise is resolving
Observables have synchronous handlers:
let observable = new Observable((observer) => {
observer.next("next being called");
});
console.log("START");
observable.subscribe(value => console.log(value));
console.log("END");
Output
START
next being called
END
The synchronous nature of Observables ensures code execution waits for Observable events unless async functions are deliberately used.
Promise vs RxJS
The RxJS library, which implements Observables, is part of the broader ReactiveX initiative aimed at bringing reactive programming concepts to multiple programming languages.
RxJS operators can manipulate and transform the data streams managed by Observables (e.g., map(), filter()). This capability doesn't have an equivalent in native Promise-based workflows.
Conclusion
Both Promises and Observables are effective for handling asynchronous processes in JavaScript, but their differences make each suited for specific types of tasks. The greater flexibility and functionality of Observables, particularly with the use of RxJS, make them a powerful choice in complex scenarios.
FAQ
Why are Promises considered unicast while Observables are multicast?
Promises represent a single operation with a single value emission. Observables can multicast by running a separate execution path for each subscription, providing different results or states.
Can Observables be used without RxJS?
No, in JavaScript, Observables are typically tied to the RxJS library, which implements the Observable interface as part of the broader ReactiveX pattern.
What is the greatest advantage of Observables over Promises?
Observables shine in their ability to emit multiple values over time and be manipulated with a rich set of functional operators, making them highly suited for managing complex asynchronous data flows.

