Lets start with promises
In Javascript, Promises are a common pattern used to handle async code elegantly. If you don't know what promises are, start there. They look something like this:
todoService.getTodos() // this could be any async workload
.then(todos => {
// got returned todos
})
.catch(err => {
// error happened
})
The important parts:
todoService.getTodos() // returns a Promise
Lets forget about how getTodos()
works for now. The important thing to know is that lots of libraries support Promises and can return promises for async workloads like http requests.
A Promise object implements two main methods that make it easy to handle the results of the async work. These methods are .then()
and .catch()
. then
handles "successful" results and catch
is an error handler. When the then
handler returns data, this is called resolving
a promise, and when it throws an error to the catch
handler, this is called rejecting
.
.then(todos => { // promise resolved with successful results })
.catch(err => { // promise rejected with an error })
The cool thing is, then
and catch
also return promises so you can chain them like this:
.then(todos => {
return todos[0]; // get first todo
})
.then(firstTodo => {
// got first todo!
})
Here's the catch: Promises can only resolve OR reject ONCE
This works out alright for things like http requests because http requests fundamentally execute once and return once (success or error).
What happens when you want an elegant way to stream async data? Think video, audio, real-time leaderboard data, chat room messages. It would be great to be able to use promises to set up a handler that keeps accepting data as it streams in:
// impossible because promises only fire once!
videoService.streamVideo()
.then(videoChunk => { // new streaming chunk })
Welcome to the reactive pattern
In a nutshell: Promises are to async single requests, what Observables are to async streaming data.
It looks something like this:
videoService.getVideoStream() // returns observable, not promise
.subscribe(chunk => { // subscribe to an observable
// new chunk
}, err => {
// error thrown
});
Looks similar to the promise pattern right? One major difference between observables and promises. Observables keep "emitting" data into the "subscription" instead of using single use .then()
and .catch()
handlers.
Angular's http client library returns observables by default even though you might think http fits the single use promise pattern better. But the cool thing about reactive programming (like rxJS) is that you can make observables out of other things like click events, or any arbitrary stream of events. You can then compose these streams together to do some pretty cool stuff.
For example, if you want to refresh some data every time a refresh button gets clicked AND every 60 seconds, you could set up something like this:
const refreshObservable = someService.refreshButtonClicked(); // observable for every time the refresh button gets clicked
const timerObservable = someService.secondsTimer(60); // observable to fire every 60 seconds
merge(
refreshObservable,
timerObservable
)
.pipe(
refreshData()
)
.subscribe(data => // will keep firing with updated data! )
A pretty elegant way to handle a complex process! Reactive programming is a pretty big topic but this is a pretty good tool to try and visualize all the useful ways you can use observables to compose cool stuff.
note: this is untested pseudocode written for illustration purposes only