RxJs is one of the vast topics in itself that we can write a complete article about. I have seen and read many articles with some important and limited topics with some code snippets but couldn’t find one such piece with a complete brief about it. So, here we go for something different.
Here we go::
=> The term RxJs stands for Reactive Extensions For Javascript. It allows us to work with an asynchronous data stream. It provides one core type:
I.e., Observable, and the other three types are Observer, Schedular and Subject.
So, we use Observables to perform asynchronous operations and handle asynchronous data. We can manage asynchronous operations in Angular using either Promises or Observables. Now, what are asynchronous operations and asynchronous data? We already know that JavaScript is a single-threaded programming language, meaning the code is executed line by line.
Once one code is complete, only the next code in the program will be executed. So, if a task takes a long time in execution, we are making HTTP requests to the server. In that case, it is going to take some time. So, the next statement after that HTTP request will have to wait for its execution; it will only get executed when the HTTP request completes.
So, we can say that the synchronous code is blocking in nature, and this is because asynchronous programming comes into the picture. An asynchronous code runs in the background without stopping the execution of the code in the main thread. So, an asynchronous code is non-blocking. That means we can make HTTP requests asynchronously.
Related Read: Setting Up Axios Interceptors For HTTP Calls With Refresh Token
In that case, it will run in the background, and the next code after that HTTP request will get executed immediately in the main thread. So, in this case, the HTTP request will not block the next line of code. Using an asynchronous program, we can perform long network requests without blocking the main thread.
We can do this in two ways:
1. By using Promises
2. By using Observables
Let’s say we are creating an application that needs data from the server, e.g., requesting a list of users from the server. In that case, we will send a request to the server from our application. Now, the server will get data from the database or web API.
So, the data we are requesting is huge. In that case, the server will take some time to gather its data. And once the data is available, it will create a response and send that data with the response to the client. So, here the server gathers all the data, and once it is ready, it sends all the data to the client. This is how a “Promise” works.
A Promise promises us some data, and it provides us the data over time, and it provides the data once complete data is ready. This is how a Promise works and deals with asynchronous data.
Let’s say we are making an HTTP request to the server to get all the users from our database so that the server will collect the data from the database or the Web API. The observable will not wait for the complete data to be available.
An Observable streams the data, so it will send the data in packets; when some of the data is available, it will send the data, then again, it will collect the rest of the data and send it with the response.
It sends the data in chunks. It is not waiting for all the data to be available and then sending the data at once, it is streaming the data, and that is what the difference between a Promise and an Observable is!
Rxjs has two main players: the Observable, the stream of data, and the observer, which will use that data. To make this observer use the data immediately by this observable, the observer has to subscribe to that observable. So, we can also say that the observer is the subscriber of the observable.
import { Component, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent implements OnInit { title = 'rxjs'; myObservable = new Observable((observer) =>{ console.log('observable') // Emit some data // to emit the data on this observer, we can call next() observer.next("1") observer.next("2") observer.next("3") observer.next("4") }); // The observable will only emit the data if it has subscriber, so let's create a subscriber for myObservable ngOnInit(){ // the subscribe() takes 3 optional parameters and these are callback() this.myObservable.subscribe((val) => { console.log(val,"::val"); }); // the next parameter is a callback() & it gets executed every time the next() returns a value // in this example we are subscribing myObservable, this next callback() will be called 4 times } }
Here, we can see that the data has been streamed one by one. This is how the observable works.!
We use operators a lot when dealing with RxJs, so it’s important to understand what operators are and how we can use them on an Observable. So, operators in RxJs are simply functions that take an Observable as an input, transform it into a new Observable, and then return it.
We use operators to manipulate the observable data stream. Let’s have a look at some operators of RxJs:
The map operator transforms the data whatsoever coming from the server. The transformation operator is basically used to transform the items emitted by an observable by applying a function to each item.
As we can see in the below code snippet, we are creating an observable using the ‘from’ operator and to the from an operator, we are passing an array, and the array contains 5 values. So the observable from operator create will emit those 5 values present in the array i.e., 1, 2, 4, 6, 8. And after emitting all data, it will also emit a complete signal because we have created this observable using this operator.
Now, using an operator, we can transform the data returned by this observable, and then we can return a new observable with the transformed data. So, this observable returns 1, 2, 4, 6, 8. Now, what we want is, we want to transform the data emitted by this observable.
Let’s say we want to multiply each of the values emitted by this observable by 5, and then we want to return the transformed data. So, the new observable will return 5, 10, 20, 30, and 40. Such things can be achieved by using operators on this observable. So, we are using a map operator to achieve this.
The map operator is a function that takes a callback function as its argument. And this callback function is going to receive a value. It will receive a value the source observable will emit, i.e., myObservable. Now, this map operator will return a new observable, and that new observable will emit the transformed data from the source observable.
Related Read: Introduction To Mapbox With React
So, we have assigned it to a new property i.e transformedObs. So, this transformedObs will emit the transformed data i.e 5, 10, 20, 30, 40. And we subscribed to transformedObs instead of myObservable. And we will get the transformed data.
import { Component, OnInit } from '@angular/core'; import { from, Observable, of} from 'rxjs'; import { map } from 'rxjs/operators'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent implements OnInit { title = 'rxjs'; arr1 = [1,2,4,6,8]; arr2 = ['R', 'A', 'S' ]; // Created an observable through from operator and passing an array myObservable = from(this.arr1); // 1, 2, 4, 6, 8 => 5, 10, 20, 30, 40 transformedObs = this.myObservable.pipe(map((val) => { return val * 5; })) ngOnInit(){ this.transformedObs.subscribe((val) => { console.log(val,"::val"); },(error) => { alert(error.message); },() => { alert('Observable has complete emitting values ') }); } }
Here’s the output:
A filtering operator filters data emitted by the source observable according to the specified condition. Let’s say, from the above-transformed data, we only want to emit data that satisfies a condition. Let’s say we only want to emit those data, which is either >= 30.
So, here we only want to emit 30 and 40. So basically, we want to filter some data on a given condition from this data. For that, we can use the filter operator.
import { Component, OnInit } from '@angular/core'; import { from, Observable, of} from 'rxjs'; import { map, filter } from 'rxjs/operators'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent implements OnInit { title = 'rxjs'; arr1 = [1,2,4,6,8]; arr2 = ['R', 'A', 'S' ]; // Created an observable through from operator and passing an array myObservable = from(this.arr1); // 1, 2, 4, 6, 8 => 5, 10, 20, 30, 40 transformedObs = this.myObservable.pipe(map((val) => { return val * 5; })) // Here source observable i.e transformedObs is emitting => 5, 10, 20, 30, 40 filterObs = this.transformedObs.pipe(filter((val) => { return val >= 30; })) ngOnInit(){ this.filterObs.subscribe((val) => { console.log(val,"::val"); },(error) => { alert(error.message); },() => { alert('Observable has complete emitting values ') }); } }
Here’s the output :
Here we can see that our output satisfies the condition that we have given and it returns a new observable with filtered data!
Forkjoin works similar to Promise.all in Javascript. I.e. let’s take an example:
Let’s say there are two observables. On that note, when both the observables are done, it will take the last value of the first and second data, respectively. So it combines the final values and gives the result.
We can give an array of observables in input and it will emit value once all the observables are finished loading in parallel.
import { Component, OnInit } from '@angular/core'; import { forkJoin } from 'rxjs'; import { DataService } from '../data.service'; @Component({ selector: 'app-comp1', templateUrl: './comp1.component.html', styleUrls: ['./comp1.component.scss'] }) export class Comp1Component implements OnInit { constructor( private dataService: DataService) { } ngOnInit(): void { } onClick(){ // simulate 3 requests forkJoin({ getUserById: this.dataService.getUserById(1), //user detail for id 1 getProductById: this.dataService.getProductById(1),//product detail by id 1 getCartById: this.dataService.getCartById(1) //cart detail by id 1 }) .subscribe(({ getUserById, getProductById, getCartById }) => { console.log('userDetails',getUserById); console.log('productDetails', getProductById); console.log('cartDetails', getCartById); }); } }
Here, we can see that the 3 APIs have been called in parallel.
RxJs has provided us with many more operators, which we can dive deeper into. Till then, enjoy reading this!
How to Effectively Hire and Manage a Remote Team of Developers.
Download NowMindbowser played a crucial role in helping us bring everything together into a unified, cohesive product. Their commitment to industry-standard coding practices made an enormous difference, allowing developers to seamlessly transition in and out of the project without any confusion....
CEO, MarketsAI
I'm thrilled to be partnering with Mindbowser on our journey with TravelRite. The collaboration has been exceptional, and I’m truly grateful for the dedication and expertise the team has brought to the development process. Their commitment to our mission is...
Founder & CEO, TravelRite
The Mindbowser team's professionalism consistently impressed me. Their commitment to quality shone through in every aspect of the project. They truly went the extra mile, ensuring they understood our needs perfectly and were always willing to invest the time to...
CTO, New Day Therapeutics
I collaborated with Mindbowser for several years on a complex SaaS platform project. They took over a partially completed project and successfully transformed it into a fully functional and robust platform. Throughout the entire process, the quality of their work...
President, E.B. Carlson
Mindbowser and team are professional, talented and very responsive. They got us through a challenging situation with our IOT product successfully. They will be our go to dev team going forward.
Founder, Cascada
Amazing team to work with. Very responsive and very skilled in both front and backend engineering. Looking forward to our next project together.
Co-Founder, Emerge
The team is great to work with. Very professional, on task, and efficient.
Founder, PeriopMD
I can not express enough how pleased we are with the whole team. From the first call and meeting, they took our vision and ran with it. Communication was easy and everyone was flexible to our schedule. I’m excited to...
Founder, Seeke
Mindbowser has truly been foundational in my journey from concept to design and onto that final launch phase.
CEO, KickSnap
We had very close go live timeline and Mindbowser team got us live a month before.
CEO, BuyNow WorldWide
If you want a team of great developers, I recommend them for the next project.
Founder, Teach Reach
Mindbowser built both iOS and Android apps for Mindworks, that have stood the test of time. 5 years later they still function quite beautifully. Their team always met their objectives and I'm very happy with the end result. Thank you!
Founder, Mindworks
Mindbowser has delivered a much better quality product than our previous tech vendors. Our product is stable and passed Well Architected Framework Review from AWS.
CEO, PurpleAnt
I am happy to share that we got USD 10k in cloud credits courtesy of our friends at Mindbowser. Thank you Pravin and Ayush, this means a lot to us.
CTO, Shortlist
Mindbowser is one of the reasons that our app is successful. These guys have been a great team.
Founder & CEO, MangoMirror
Kudos for all your hard work and diligence on the Telehealth platform project. You made it possible.
CEO, ThriveHealth
Mindbowser helped us build an awesome iOS app to bring balance to people’s lives.
CEO, SMILINGMIND
They were a very responsive team! Extremely easy to communicate and work with!
Founder & CEO, TotTech
We’ve had very little-to-no hiccups at all—it’s been a really pleasurable experience.
Co-Founder, TEAM8s
Mindbowser was very helpful with explaining the development process and started quickly on the project.
Executive Director of Product Development, Innovation Lab
The greatest benefit we got from Mindbowser is the expertise. Their team has developed apps in all different industries with all types of social proofs.
Co-Founder, Vesica
Mindbowser is professional, efficient and thorough.
Consultant, XPRIZE
Very committed, they create beautiful apps and are very benevolent. They have brilliant Ideas.
Founder, S.T.A.R.S of Wellness
Mindbowser was great; they listened to us a lot and helped us hone in on the actual idea of the app. They had put together fantastic wireframes for us.
Co-Founder, Flat Earth
Ayush was responsive and paired me with the best team member possible, to complete my complex vision and project. Could not be happier.
Founder, Child Life On Call
The team from Mindbowser stayed on task, asked the right questions, and completed the required tasks in a timely fashion! Strong work team!
CEO, SDOH2Health LLC
Mindbowser was easy to work with and hit the ground running, immediately feeling like part of our team.
CEO, Stealth Startup
Mindbowser was an excellent partner in developing my fitness app. They were patient, attentive, & understood my business needs. The end product exceeded my expectations. Thrilled to share it globally.
Owner, Phalanx
Mindbowser's expertise in tech, process & mobile development made them our choice for our app. The team was dedicated to the process & delivered high-quality features on time. They also gave valuable industry advice. Highly recommend them for app development...
Co-Founder, Fox&Fork