Angular 7 just came out! These are exiting times. When it comes to learn Angular there’s a common pitfall I’ve seen: Not learning RxJS.
Most Angular articles and tutorials explain how to do things in Angular but those miss the foundations in which Angular is built on top of. I’m talking about RxJS, which is at least 50% of what Angular is today.
If you’re asking yourself, should I learn RxJS too? If you’re not completely confident on what’s the difference between an Observable, Subjects and BehaviorSubjects, then you definitely do. At least those three which are the most common ones to use.
The first thing here is where to look for documentation. I heavily recommend the ReactiveX site, that is, the official documentation. They have nice graphs, a bit complex to navigate, but hey, we all know how to use Google, do we?
So, for Observables, this should be the fist page to read:
The Rx library works a lot with Java, so don’t be scared if some of the docs refer you to Java. Actually the concept is the same, and to learn the idea behind it is as valid as any other programming language. RxJS has sometimes a different API in some places, but it is consistent across languages in 95% of it.
Let me explain with my own words what are Observables. To be as easy to understand as possible, I will oversimplify so much that some parts of the explanation would be directly wrong. Forgive me about that, it is a form of white lie, and hope it’s the journey what gets you there.
Observables are yet another implementation of producer->consumer for messages. If you’re not new to programming you should have seen this same schema in lots of other places; and Observables are not really special on their own. Like Qt connections between controls, or signal and slots.
What makes Observables special is that Rx uses them as a Swiss army knife, allowing us to chain them and determine full flows of data, really complex ones using Observables.
An Observable is something that is capable of emitting events or messages to subscribers. Any code can subscribe to any Observable and will receive their updates. The main purpose of this schema is handling events which originally come from outside of our own code. For example, the user may click a button to get the next page of data. The original event of clicking is fired outside of our control, and we want a few things happening when that’s the case.
But they can be also chained together as I said before. For example, you may load the next page of data, but you have a label for counting and paging. This label needs to be updated too whenever the main control updates. You can fire another event inside your control that other controls may listen to for updates.
Also they can be “piped”, because the messages they use to carry are not simply flags or events saying “there’s new data”, but they use to contain the data itself, you can shift to a form close to functional programming where you connect things together. So there are a bunch of functions that read from observers, compute, and emit new messages. For example you could pipe the data of the page through a len() function and the subscriber of the latter will directly get the new length of data instead.
Usually we don’t create Observables from scratch, as that would mean some kind of cooperative code that runs when subscribed. This is too close to a regular function that most people, including myself, will think it’s useless. Usually we work from some already existing Observables and pipe/chain them through the flow we want for them.
For creating really useful Observables we use Subjects instead. Subject is an extension of an Observable that allows us to push/emit items so the subscribers will receive them. There are several flavours of them, and BehaviorSubject is one of the most useful ones.
I heavily recommend reading these article for Subjects:
The main and crucial difference between Observables and Subjects is that Observables will execute the underlying code for each subscription, it’s like “on subscribe, do this”. Subjects on the other hand share the same result to all it’s subscribers, which is really closer to this producer->consumer I referred before.
The main documentation for those is here:
Before diving further, I need to explain a bit more on Observables themselves. They are a base tool for asynchronous code calls or cooperative code. Whenever you subscribe to them, their code is executed, and you may start receiving messages. On these messages, there is an special one, the “Completed” message. The subscriptions are not permanent until you unsubscribe them, they can be finished as well if the source says that has finished producing. And of course you can unsubscribe too (and you should).
Think about them like phone calls. An observer is just a number you can dial. When your code subscribes it is dialling to the observer, they pick up and start talking to your code, and when they have finished saying whatever they wanted to say, they hang up. You can hang up on them too, by unsubscribing. But apart of he dial and hang up, you have no means of communicating with them. It is a one way communication.
The messages passed can be as simple as one boolean flag, to entire databases passed per message. It’s up to you how to construct these. Also, it is possible send/receive messages with no contents, you will just receive the function call, no parameters.
Remember that the Observer completing (hanging up) it is itself a form of message, you will get no callback for that, but you’ll see this into play with Subjects and Pipes. (In fact, you can get a callback, just is not the regular onNext, it’s the onCompleted one)
We got this? Let’s jump back again to Subjects!
There are four types of Subjects: AsyncSubject (In RxJS they are named just “Subject”), BehaviorSubject, PublishSubject and ReplaySubject.
Everyone starts with AsyncSubject (maybe because it comes first alphabetically, who knows), but these are kind of special case. So I’ll reorder those in a way it makes the most sense to learn.
PublishSubject: (In RxJS is called just Subject) Whenever they have a new message, they broadcast it to all its subscribers. If you subscribe later, you’ll miss the previous messages. Kinda like a radio, you tune to it and start listening; but forgot about all the past data that you may have missed. Almost like an observable, but a new subscription triggers nothing, and each message is copied to all subscribers instead of recalculating it.
Say we use those to send new updates to several controls, that’s nice because every control gets its own copy without triggering the whole thing again; less computation, and also one HTTP call serves all controls. But if one control joins later, will remain clueless on which data there is until a new update is fired.
BehaviorSubject: They are just like PublishSubjects but they keep the last message in memory to share it on new subscriptors. So the primary difference is that they also act on the new subscriptions. The side effect of this behavior is that they require an initial value; so every new subscription is guaranteed to get data straight away.
But what if what we are sending are not full messages but incremental ones? For example, we may want instead of sending a full table of data each time, instead we’re sending the new rows or row updates, one at a time. The initial value here would make no sense, and BehaviorSubjects will lose all old messages anyway, excepting the most recent one.
ReplaySubject: Again, like PublishSubjects, but they store all messages since inception, and on subscription, they replay them to the subscriber. Once subscribed and the replay happened, it will relay all new updates as the regular PublishSubject. So in the example before, we could use these type of Subjects and if a control joins later, it will get all the deltas that happened up to now. If the code joins early, they get no updates whatsoever, as no update or message arrived yet. This should play nicely on this use case.
Remember I said before that Observer having Completed (hanging up on subscribers) it itself a form of message? Then what if we don’t care much on the intermediate messages, and we just want to know when it has completed?
AsnycSubject: Waits for completion, and then broadcasts the last message received to its subscribers. This is close to how an HTTP call could be managed; we just wait until it returns. It is like a deferred function, just it shares the result to all its subscribers. The main benefit of this one is, if it failed, our code would never be called and the exception would be raised. With the other flavours, if you subscribe early enough, you’ll get the updates first, and the exception afterwards. This is the only one that guarantees that either there is a message plus completion signal, or an exception.
Enough for now, let this settle a bit, read on the docs I pointed and google about those, there’s lots of good articles with practical examples.
Hope I can get time to write about Pipes, those are important as well. Until then, thanks for reading!