RxJS Operators
One of the greatest feature of RxJS is its rich and powerful operators. They are methods/functions that do not change existing stream but return a new one. In other words, an operator is a pure function in which input is an Observable and output is another Observable.
The notion and implementation of pure functions with specific, explicit input, output and immutability embrace functional programming principles. This declarative style greatly reduces side effects and improve code readability. The first part of this series clarified those in great details 🕵 ️🤗
Creation operators
RxJS operators are grouped based on their distinctive purposes. Its categories include: creation, transformation, filtering, combination
, etc.
In a RxJS program, the first and foremost phase is to create a stream. RxJS treats every data source as stream. Therefore, its creation operators allow us to create a data stream from almost everything. They include simple DOM events such as button clicks, input keypresses to more complicated data sources like Promises.
In this blog, I would like to introduce first four primary RxJS creation operators: create, from, fromEvent, of
and more importantly, their real-world usages. Now, let's grab a cup of coffee ☕️ and dive into it 🕵 ️
Create operator
create
is a low-level machenisim allowing us to create any Observable. It is the most generic and thus powerful among creation operators that we will dive in today.
Data source
create
does not receive values as data source but a list of events called function subscriptions. These functions will instruct how values get emitted to observer.
import { Observable } from 'rxjs'
const observable = Observable.create(subscriptionFn)
create
essentially gives you complete control over the data source. But how? 🤔
By taking a look at the official docs, we could see that create
accepts a parameter - a onSubscription
function. This function accepts an observer and explicitly use next
, complete
and error
to emit a value, finish and throw an error respectively when an observer subscribes to it.
Let’s see how create
controls the flow of data source in action:
In above example, we only emit odd numbers to observers. Thanks to next
function, every value that meets our condition gets distributed. Otherwise, an error is thrown by error
method. Eventually, we call complete
to notify observers that the observable has finished emitting and the process is done.
Note that after either complete
or error
is called, the observable will stop emitting and not doing anything else. This termination is called Observable Contract.
Cleaning up before unsubscribing
onSubscription
parameter of create
operator can optionally return
function. By using this, we could clean up resources before unsubscribing from original observable.
Do you really need create
?
The answer is no most of the time!
There are other creation operators that we will look at and see how powerful and flexible they are. Besides, RxJS also has a wide range of other operators for filtering, transforming, error handling…etc. Therefore, create
is only necessary when you really need that level of control over the data source of the observable.
From operator
from
operator turns array, Promise or iterable into an observable (stream). The closest real-world scenario would be to create an Observable from Promise. Let’s create a stream from getCakes
Promise via Fetch API:
Now you might wonder: Is it this simple? Well, yes but no 🤗.
Lemme get this straight. It is simple once your mindset shifts to a data-driven model. Meaning your program does not really care about where or how fetchCakesPromise
is call/executed. All it pays attention to is there is a stream of cakes flows through and it need to distribute each value that the stream emits to its subscribers. As long as its observer - subscriber got their required data, mission gets completed!
fromEvent operator
fromEvent
creates an Observable from events. One of the most simple implementation of fromEvent
is to create a stream of mouse clicks
events. Let's see it in action 🖱🐭
You can easily notice that fromEvent
take first argument as a DOM node submit button. The second argument is essentially name of the event, which in our case is click
.
From this simple example, it is difficult to understand why we need RxJS to handle this simple click
event. However, things get more interesting when we do not stop at a one-operation-handler.
In RxJS, regardless of simple or complicated flow, we always treat data source as a stream. fromEvent
is kind of a gateway for transforming pure DOM events into a stream. Only after that we could use other powerful RxJS operators to reshape and handle logics in the flow.
of operator
of
transforms a list of values into an observable sequence. Values as arguments could be a sequence of number, an object, an array. At this point, you might find off
oddily similar to from
. Let's dig out difference between them 🕵️♂️
It did not take long for you to spot the difference didn’t it? We could see that of
does not flatten the source. Thus, it emits the whole value of numberArray
at once. On the other side, from
performs the flattening of the array source before emitting values. It therefore distributes each value from numberArray
one by one.
Key takeaways
create
is a low-level Observable factory that gives total control over how values get emitted to observerscreate
is over-killed in many situations. So it is worth considering the cost of complicating your API.from
turns array, promise or iterable into an ObservablefromEvent
turns event into an Observable- When we use either
from
orfromEvent
to create a new stream. RxJS only cares about values that the stream produces, not each individual event. of
transforms a list of values into an observable sequence. In comparison withfrom
,of
does not flatten the data source. Thus, it emits each argument as a whole instead of one by one