Sebastian Gomez
Implementing of as an operator in Observables
In this post we are going to increase the number of operators we can implement and use inside an Observable by creating the of operator. Basically, it will be an observable generation operator so that we can turn data into observables.
Earlier, we explored implementing the filter operator and the map operator on observables, building them from scratch in a way similar to how RxJS does it. That helped us understand a bit more about the philosophy and inner workings of observables. If you haven't read them yet, I recommend reviewing those two posts in the series before continuing, since we will follow the same idea of reconstructing an operator from scratch.
Example of using the of operator
Before implementing it, let's see how it would be used. Let's start with the modern RxJS form, which is what you will find in most projects today. In current RxJS, of is a standalone function you import directly from the library.
// Modern RxJS form: of is a standalone function imported from 'rxjs'
import { of } from 'rxjs';
// Creates an Observable from the value 5 using the of function
const fancyObservable = of(5);
// Subscribes to the Observable and logs each emitted value
const fancySubscription = fancyObservable.subscribe({
next(e) {
console.log(e);
},
});Note: The Observable.of(5) form you will see next is the static API from before RxJS 6 (2018), which has already been removed from the library. We use it here on purpose because we are going to reimplement the operator from scratch as a static method of our own Observable class, for educational purposes. The current equivalent in RxJS is the standalone of(...) function you saw above.
With that clarification, here's how it would look using our static reimplementation:
// Creates a constant "fancyObservable" holding an Observable created with the "of" method and the value 5 as argument
// Note: here of is a static method on our own Observable class (educational reimplementation)
const fancyObservable = Observable.of(5);
// Creates a constant "fancySubscription" holding a subscription to "fancyObservable"
const fancySubscription = fancyObservable.subscribe({
// Defines an object with a "next" method that accepts an argument "e"
next(e) {
// Logs the value of argument "e" to the console when the "next" method is called
console.log(e);
},
});You might be wondering, why is this important? What's the point of turning an already unwrapped value into an Observable? The most immediate answer is that, sometimes, you need to combine "pure" data with data coming from Observables. Later we'll see ways to combine observables, but we have no way to combine "pure" data with observables without first turning that data into Observables.
Implementing the of operator
To implement the of operator, we are going to create it statically, meaning this function will be tied to the prototype regardless of whether an instance of an Observable exists or not.
// Defines a static method "of" inside a class (for example, the "Observable" class), accepting an argument "value"
static of(value) {
// Returns a new instance of the "Observable" class (or the class that contains this static method)
return new Observable(function subscribe(observer) {
// Calls the "next" method on the "observer" object and passes the "value" argument given to "of"
observer.next(value);
// Calls the "complete" method on the "observer" object to signal that no more values will be emitted
observer.complete();
// Returns an object that contains an "unsubscribe" method
return {
// Defines the "unsubscribe" method which, in this case, does nothing
unsubscribe() {},
};
});
}Note: The real RxJS of accepts multiple values, for example of(1, 2, 3), and emits them one after another. Our teaching version emits a single value to keep the example simple. As an exercise, later on you could extend it to accept several arguments and loop over them emitting each one.
That's it
I hope this post is useful to you and that you can apply it to a project you have in mind, or that it simply helped you understand the nature of operators over observables.
What we learned
- We learned how to create the of operator to turn data into observables.
- We saw that the of operator is useful when we need to combine "pure" data with data coming from Observables.
- We implemented the of operator statically on an Observable's prototype, remembering that in modern RxJS
ofis a standalone function imported withimport { of } from 'rxjs'.
Suggested exercises
- Implement the of operator in a project you are working on and analyze how it improves combining "pure" data with observables.
- Extend your version of of so it accepts multiple arguments, just like the real RxJS
of, and emits them one by one. - Experiment with other operators on Observables, such as
concat,mergeorswitchMap, and analyze how they work together with the of operator. - Build a small project that uses the of operator to perform asynchronous operations, such as API calls.
If you managed to implement it, want to add some other functionality, or have any questions, feel free to leave me a comment below. Remember that if you liked this post, you can also share it using the social media links below. See you next time!
Sebastian Gomez
Creador de contenido principalmente acerca de tecnología.