So before I begin, it helps to get a understanding of the history behind RxJS.
The RxJS library also uses Functional Programming to implement operators and functions for managing sequences of events (streams). For a great intro to Functional Prgoramming I highly recommend watching Russ Olsen’s video at GOTO 2018.
Imperative vs Declarative
When you hear people discuss RxJS, you commonly will hear them referring to imperative and declarative coding.
Imperative refers to code that you write in a specific way. This is code that you have manually piped the control flow similar to the way Promises work.
These definitions will be more apparent to you later on in this post, but its good to introduce them here.
When explaining RxJS it typically is easiest to do by showing code first.
Most people are typically familiar with a Promise implemented as follows:
Nothing super exciting here, just using the standard “resolve/reject” syntax. After the promise completes the output message is written to the console.
Now compare that to this:
Woah! What’s that? Well that’s RxJS! If you notice, the declarative practice is being used as the observable is first defined, and then the different hooks in the observer are used with
I’m going to come back to this example later in this article, but just wanted to introduce it first.
How does RxJS work?
So to start with RxJS, it helps to first have a few definitions:
- Observable = a defined stream of events
- Subscription = represents the actual execution flow of events (initiating a subscription basically “turns on” the execution)
- Operators = are “pure” functions that can invoke flows with subscriptions. These have different forms that can either create a stream or reproduce a stream in a pipeable flow.
- Subject = an event emitter that can be used for multicasting. These are special and used so that you can essentially inject emitters in your programs.
- Schedulers = these help with concurrency and are really a more advanced RxJS topic. I’m just including it here for completeness.
For more info and examples please refer to the official RxJS Getting Started Guide here.
So with that vocabulary introduced, now we can formally discuss the example I introduced earlier.
So lets go back to the code that I showed before:
This is a great example because it shows you an implemented Observable.
If you notice first you define the Observable with
complete. Then when I start the execution flow with the
subscribe I include definitions for what to do with the execution flow:
- next = does a
console.logof what is returned from the stream
- error = does a
console.logif an error occurs in the stream
- complete = writes
doneto the console when execution is finished
This is one way to define an observable directly. Each observer has the three hooks of
complete that you can use to define execution behavior.
Obserables are great, but RxJS also offers operators which make defining observables much easier.
With operators there are two types:
- creation operators = generated observables with predefined behavior
- pipeable operators = observables that return other observables using the syntax “.pipe”
Here’s a creation operator in action:
Here we are using the
of operator to emit values of
30 in a sequence. This is super basic, but gives you an idea of how you could use this to emit a set of values in a stream without needing to manually define the observer hooks.
Here’s a pipeable operator in action:
So here, its a little more complicated, but I think you can figure it out.
- We’re using the creation operator
ofthat I referenced before to generate a stream of values
- Next we take the output from
ofinto the pipeable operator
- Then we’re letting
mergeMapcreate a new observable and pipe it into
intervaltakes the output and
console.logeach value after a 1 second delay
So basically this creates a flow with the
pipeable operators. The original source observable is used to recreate a new observable with added logic.
An easier way to think of this is as a
stream is being defined here. Each pipe that is used with the stream adds value.
A more literal way to think of pipeable operators is as water flows through a set of pipes. Each pipe adds value to the water until it exits the flow.
Visually you can see this flow in the following diagram:
For a better visual of flows with RxJS, many people rely on Marble Diagrams. They’re a little daunting at first, but if you learn how to read them with the RxJS Guide they really help. I recommend checking out the RxJS guide at the bottom of the operators page here.
Subscriptions and Memory Leaks
So one big challenge that developers run into with RxJS is memory leaks with subscriptions.
Memory leaks are when you’ve forgotten to “unsubscribe” from a stream, and the process continues to run eating up your memory. Memory leaks can quickly eat up your browsers memory and slow down your application.
The best solution is to always make sure you have a
.unsubscribe for your observables. You also can rely on prebuilt mechansims in frameworks like Angular’s
Here’s some code that creates a memory leak:
This code can easily be fixed by adding a
setTimeout that unsubscribes from the stream after a set interval of time like so:
I actually contributed an article on the RxJS DEVTO blog on this topic titled “Common Approaches to Handling Subscriptions” here. I highly recommend checking out my post when you have some time.
So far we’ve just covered some basic execution flows. If you combine RxJS operators, you can define some pretty complicated work in just a small amount of code.
The challenge happens when you create a group of Observables from a single Observable. This is called a Higher Order Observable. RxJS has operators that help you with flattening these situations to include:
I’m not going to dive into a deep example of Higher Order Observables here because I think it goes beyond the scope of an introductory article. I do, however, highly recommend checking out the RxJS Guide on operators that discusses this in more detail.
I also cover a more advanced topic in my RxJS DEVTO blog site post “From Promises to Observables” here. In that case I walkthrough setting up a
scan operator to combine several HTTP calls.
I recommend reading posts on the RxJS DEVTO blog site for more advanced Observable cases and discussion as well.
My discussion in this post has just covered the surface of what you can do with RxJS. There are also lots of great materials and videos available on line that provide in depth walkthroughs and examples.
I recommend checking out these videos as a good place to start:
- GOTO 2018 – Functional Programming in 40 Minutes – Russ Olsen
- Ng-Cruise – RxJS By Example with Ben Lesh
- Creating an Observable from Scratch (live-coding session) – Ben Lesh
I hope this post has helped you with learning RxJS. In this post I walked through what RxJS is, and ways you can use it in your programs.