For a long time in JavaScript, handling asynchronous values has come down to callbacks or Promises. Being an asynchronous primitive, Promises are often compared to RxJS Observables. To illustrate the difference between Promises and Observables, let us write a promise from scratch.
const myPromise = new Promise((resolve) => {
setTimeout(() => {
console.log("myPromise timeout hit")
resolve(100)
}, 1000)
console.log("myPromise started")
});
myPromise.then((response) => console.log({ response }));
As soon as we run our code. the promise will start executing without any delay.
In other words by the time have access to myPromise
object, it has already been executed. Even if we omit the last line with .then
call, the promise will still execute except now our resolve call will not do anything as we are not providing in the .then
callback.
Now let us see how Observables behave in the same scenario. We’ll pretty much use the same code except now we’ll use subscribe
from RxJS which allows an observer to get attached to the observable execution.
const myObservable = Observable.create((observer) => {
setTimeout(() => {
console.log("myObservable timeout hit");
observer.next(100);
}, 1000);
console.log("myObservable started");
});
myObservable.subscribe((x) => console.log(x));
The output will be similar to as if we are using Promises.
So where’s the difference here?
To see the difference between Promises and Observables, remove the last line from the above example i.e. omit the call to subscribe and run the code again.
myObservable.subscribe((x) => console.log(x)); // remove this line
If you’ll check the console this time, nothing gets printed on the console indicating Observables are lazy and they won’t execute until we subscribe to them. But what advantage do we have with Observables having this lazy feature?
This is where it gets interesting.
If we were using a promise, it is always going to fire the block that's inside of it. For instance, If we are setting up some asynchronous call, the instant you have a promise it's going to fire that asynchronous call, setting up some event handler, or anything else. That is already done by the time you have access to the promise.
On the other hand, If I have an Observable, the Observable will not execute itself unless we subscribe to it. Moreover, it is also possible to cancel the execution of an Observable, something which is not possible with promises.
Let us see how we can cancel an Observable mid-way through its execution. Considering the above example, the call to subscribe
returns an object called subscription
. The Subscription represents the ongoing execution and has a minimal API that allows you to cancel that execution. With subscription.unsubscribe()
you can cancel the ongoing execution.
Each Observable must define how to dispose resources of that execution when we create the Observable using create()
. We can do that by returning a cleanup function from within an observable.
const myObservable = Observable.create((observer) => {
const id = setTimeout(() => {
console.log("myObservable timeout hit");
observer.next(100);
}, 1000);
console.log("myObservable started");
return () => {
console.log("unsubscibing myObservable");
clearTimeout(id);
};
});
const subscription = myObservable.subscribe((x) => console.log(x));
setTimeout(() => {
subscription.unsubscribe();
}, 500);
Notice how the Observable starts executing but as soon as it is unsubscribed after 500 ms, we clear the timeout and the inner setTimeout
callback is never executed.
Observables can embody the setup and teardown for their data sources. What does that mean? That means, unlike Promises, Observables can be canceled because they embody everything necessary to tear themselves down.
Likewise, because Observables embody everything necessary to set themselves up they can be called again as long as we have access to them. So if we were to call a promise again, it's not going to run again. It's just going to return the same value it already had.
This means if we have an Observable that's errored, we can simply subscribe to it again to retry it or use one of the retry operators such as retry()
from RxJS. Whereas with a Promise if the Promise has errored, we better have access to whatever function returned the Promise because the Promise has already executed its logic.
Thank you for reading!
I hope this post was useful to you and helped you understand the difference between RxJS Observables and JS Promises.
Feel free to reach out to me! 😊
Top comments (0)