JavaScript Observables in 5 Minutes
Observables are just one way to work with async JavaScript. For alternatives be sure to check out Observable vs Promise..which is better?
What are Observables?
Observables are functions that throw values. Objects called observers subscribe to these values. Observables create a pub-sub system based on the observable design pattern. This makes observables popular with async programming in modern JavaScript frameworks like Angular and libraries like React.
Unlike Promises, observables are not yet inherent to JavaScript. This is why Angular and React rely on the RxJS library for implementing observables. RxJs stands for "Reactive Extension for JavaScript". The RxJS library defines its own Observable class along with supporting methods for Reactive programming.
While you can easily use observables by importing the RxJS library, it's easier to understand how observables work by implementing your own Observable class:
class Observable { constructor(functionThatTakesObserver){ this._functionThatTakesObserver = functionThatTakesObserver; } subscribe(observer) { return this._functionThatTakesObserver(observer) } } let myObservable = new Observable(observer => { setTimeout(() => { observer.next("got data!") observer.complete() }, 1000) }) let myObserver = { next(data) { console.log(data) }, error(e) { console.log(e) }, complete() { console.log("request complete") } } myObservable.subscribe(myObserver) // (1 second) got data! // (1 second) request complete
This is a basic example of how an Observable works and is largely based off Netanel Basal's JavaScript - Observables Under The Hood.
Notice how we first define an Observable class. The class takes a single constructor argument functionThatTakesObserver:
class Observable { constructor(functionThatTakesObserver){ this._functionThatTakesObserver = functionThatTakesObserver; } }
Within our class definition, we also define a subscribe() method. Notice how this method simply takes an observer as an argument and passes it to our constructor function functionThatTakesObserver:
subscribe(observer) { return this._functionThatTakesObserver(observer) }
After defining our Observable class, we instantiate a new instance of Observable and assign it to myObservable. Notice how we pass in a function that takes an observer object as a parameter.
let myObservable = new Observable(observer => { setTimeout(() => { observer.next("got data!") observer.complete() }, 1000) })
In this example, we've used setTimeout() to mimic an async HTTP request. After the operation completes, we call the next() and complete() methods on the observer we passed in.
We then define an observer object myObserver which implements the three callback methods, or notification types, an observable can send:
let myObserver = { next(data) { console.log(data) }, error(e) { console.log(e) }, complete() { console.log("request complete") } }
Note that next() is the only required method for RxJS.
Once we've defined the observer object myObserver, we execute the observable by calling it's subscribe() method:
myObservable.subscribe(myObserver) // (1 second) got data! // (1 second) request complete
By calling subscribe() on myObservable, we fire the constructor function passed to the observable instance and register the callbacks as defined in our observer myObserver.
That's it! This represents the basics of implementing the observer design pattern in JavaScript and demonstrates how to gracefully handle async activity using observables. Continue reading for an even deeper dive into using observables in modern JavaScript programming.
Observables: A deeper dive...
What are Observables?
Observables represent a progressive way of handling events, async activity, and multiple values in JavaScript. Observables are really just functions that throw values. Objects called observers define callback functions for next(), error(), and complete(). These observer objects are then passed as arguments to the observable function. The observable function calls the observer methods based on a certain behavior (AJAX HTTP request, event, etc). This allows the observer to "listen" for state changes emitted by the observable function.
Why Observables?
Observables have surfaced through an evolution of handling async activity in JavaScript. While the Promise API has largely replaced the world of nested callbacks, observables demonstrate the next step forward in gracefully handling async activity and real-time events. In her article An Introduction to Observables for Angular Developers, Jen Looper does a great job explaining this evolution and the progressive need for the observable design pattern in JavaScript.
Reactive Programming
Observables implement reactive programming principles. Reactive programming is a programming paradigm involving async data streams and the propagation of change.
Observables represent these streams of data. Observers represent the registered callbacks used for listening or "subscribing" to changes in these streams.
Javascript Observables vs Promises
Those more experienced with Promises may ask "Why Observables?". After all, Promises are designed around handling async activity in a graceful way.
Everything you can do with a Promise you can do with an Observable. Everything you can do with an Observable you can't necessarily do with a Promise. Here are some of the key differences between Observables and Promises in JavaScript:
Eager vs Lazy
A promise will execute at the moment it's defined. When a promise has been initialized, it represents a process that has already started happening.
An observable defines a function that's executed only when subscribe() is called. You have to call subscribe() on an observable before the code will actually execute. This saves resources as observables only execute when they are subscribed to.
Cancel vs no cancel
While some Promise libraries implement cancel functionality, the inherit JavaScript Promise is not cancellable. Just like you can subscribe to an observer, you can also unsubscribe.
Always Async vs Sometimes Async
A promise always resolves or rejects itself based on some async activity. While observables are often used with async activity (such as the Angular HTTP request client), observables can also be used for sync activities as well. For example, you can use an observable to iterate through the elements in an array.
Multicast vs Unicast
Promises are multicast. This means any reference to the promise will receive the same resolved value. Observables are unicast by default. For every observer that subscribes to an observable, a separate instance of the observable function is executed.
Things can be done to make observables multicast. The RxJs library implements a share() method for sharing the same observable instance across all subscribers. Remember that observables are unicast by nature.
Push vs Pull
A promise either resolves or rejects. It can't emit multiple values. An observable can call next() multiple times.
Because of this, observables create a pub-sub relationship where the observable "pushes" updated values to its subscribers.
Mateusz Podlasin explains these differences in more detail in his article Promises vs Observables. It's worth checking out, especially for supporting examples for each of these outlined differences.
Conclusion
Observables are functions that throw values. Observers subscribe to these functions and register callbacks to listen for updates. This results in lazy execution of async data streams popularized by Reactive programming.
While observables aren't yet inherit to JavaScript, the RxJS library implements them in popular frameworks like Angular and libraries like React.
Your thoughts?
Observables are the "2.0" of Promises in handling async activity in JavaScript. With that said, Promises can still be good if you are using libraries that work with promises.
Also promises are easier to understand and (at this point) higher chance developers have experience using Promise over Observable.
You can also use a Promise natively with JavaScript whereas Observables still require importing the RxJS library or similar implementations.
Of course this article does a great job of showing you how to create an observable from scratch. This also shows you how relatively simple the concept is underneath the hood.
i'm sorry but I'm trying to think of a reason NOT to use an Observable over a Promise in JavaScript? I mean an Observable can do everything a Promise can and more. Its like the Promise 2.o
So if anyone can tell me why Promise still has a place in this world (other than legacy support) let me know.
PS: I know Observables still aren't native to widely supported versions of JS but considering this fact (and eventual adoption)..would love to hear thoughts...
it's important to note that an observable is really a design pattern. This article does a really good job of creating an Observable from scratch but it's important to remember patterns versus implementations of those patterns.
The most popular "defacto" JavaScript implementation of the Observable pattern is RxJs. Frameworks like Angular use RxJs for Reactive forms and other framework level features. Libraries like React leverage the RxJs library in similar ways.
Great 5 minutes explanation. Implementing your own version of the Observable is a MUTS DO exercise for new developers...
when I read through the "Push vs Pull" section I couldn't help but think about the similarities to a "pull" based system like Kafka. In Kafka, consumers pull messages from topics. The advantage is Kafka just sits there so an infinite number of applications can read from Kafka in parallel.
So how does this relate to the "pull" based nature of a Promise. I suppose a Promise "pulls" the value when it either rejects/resolves.
Does anyone have similar thoughts or comparisons to make?
this took longer than 5 minutes for me to understand but wow ...great explanation.
AMAZING exercise. THANK YOU.
in depth. appreciate this explanation.
Be sure to explore async/await...it will blow your mind and is much more elegant way to handle async behavior in JavaScript.
i still don't get when you would cancel a Promise but that is just me...
Reactive programming is the future (and the past) and is the only way front ends should be "architected" today.
I think observables follow the Reactive programming manifesto and should become the standard for how events, data are consumed by client side applications.
So the Observable requires libraries and isn't native to JS?
Thank you for sharing this,
one small update here is promises are unicast I.e will execute only once and observables are multicast which means every time we subscribe to the observable, it will execute again and again.
abc
OMG huge thanks!
i still prefer the Promise myself. It's just easier to understand and work with (and native to JavaScript at this point).
When you say something like "An Observable can do everything a Promise can but not the other way around"....you should be saying "both can be used to achieve the same async activity in JavaScript
Real World Use Cases for Observables in 2022
1) Web Sockets
The RxJs library is really good for web socket connections because the client can subscribe to push notifications coming from a push based API.
2) Reactive forms / debouncing live search input
People love to use RxJs and reactive forms to control user input. This is especially useful in debouncing live search requests so you aren't overloading the server every key press.
3) Angular
The Angular framework uses the RxJs Observable library extensively in its own implementation. When JavaScript developers are using Angular in 2022 they are using Observables.