Understanding ForkJoin and MergeMap in Angular ?
Angular is a powerful framework for building single-page applications, and it provides a variety of operators to handle asynchronous operations and manage data flow. Two of the most useful operators in Angular’s RxJS-based system are forkJoin and mergeMap. These operators can be used to manage multiple observables and compose asynchronous workflows effectively.
In this blog post, we’ll take a deeper dive into these two concepts, understand how they work, and learn how and when to use them in an Angular application.
What is ForkJoin in Angular?
forkJoin is an operator in RxJS that allows you to combine multiple observables and wait for all of them to complete before emitting a single array of results. It's useful when you need to execute multiple HTTP requests simultaneously and gather the results once they have all completed.
Key Points about forkJoin:
It takes an array (or an object) of observables as input.
It waits for all the observables to complete, then emits an array of their last emitted values.
If any observable errors, the entire
forkJoinsequence will fail, and no values will be emitted.
Example Use Case
Imagine you have an Angular service that needs to make multiple HTTP requests to fetch user information and their associated posts. Instead of making these requests sequentially, you can use forkJoin to run them in parallel and wait for all responses.
Code Example with forkJoin
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, forkJoin } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class UserService {
constructor(private http: HttpClient) {}
getUserData(userId: string): Observable<any> {
const userInfo$ = this.http.get(`https://api.example.com/users/${userId}`);
const userPosts$ = this.http.get(`https://api.example.com/users/${userId}/posts`);
// Use forkJoin to wait for both requests to complete
return forkJoin([userInfo$, userPosts$]);
}
}In this example, forkJoin ensures that both the user data and posts are fetched in parallel, and the result will contain an array of responses once both HTTP requests are successful.
Output
The output of forkJoin will be an array where each element corresponds to the value emitted by each observable. In this case, the array might look like:
[
{ id: '1', name: 'John Doe', age: 30 },
[
{ postId: '101', title: 'Post 1' },
{ postId: '102', title: 'Post 2' }
]
]What is MergeMap in Angular?
mergeMap, also known as flatMap, is another powerful operator in RxJS that is often used when you need to transform each emitted value from an observable into a new observable. It merges the inner observables into the outer one, allowing you to deal with asynchronous data in a more flexible way.
The key difference between mergeMap and other transformation operators like map is that mergeMap allows you to handle observables inside an observable. If you have a sequence of asynchronous events (like multiple HTTP requests or stream events), mergeMap enables you to handle them as they arrive.
Key Points about mergeMap:
It takes an incoming observable value and maps it into an inner observable.
It flattens all the inner observables and merges them into the original observable.
It doesn’t wait for one observable to complete before subscribing to the next one.
It can be particularly useful when you want to handle multiple requests or events concurrently.
Example Use Case
Let’s say you want to process a list of user IDs and fetch their respective data asynchronously. Using mergeMap, you can map over the user IDs and fetch user data in parallel.
Code Example with mergeMap
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class UserService {
constructor(private http: HttpClient) {}
getUserDetails(userIds: string[]): Observable<any> {
return new Observable(observer => {
// Start with an observable that emits the user IDs
observer.next(userIds);
observer.complete();
}).pipe(
// Use mergeMap to handle each userId asynchronously
mergeMap((userIds: string[]) => {
return userIds.map(userId =>
this.http.get(`https://api.example.com/users/${userId}`)
);
})
);
}
}Here, mergeMap takes each userId and maps it to a new HTTP request observable. These requests will be handled concurrently, and you will get the results for all users as they complete.
Output
mergeMap will emit the values from each of the inner observables as they arrive:
{
id: '1',
name: 'John Doe',
age: 30
}
{
id: '2',
name: 'Jane Doe',
age: 25
}Each user’s data is emitted as it arrives, without waiting for the others to complete.
When to Use ForkJoin vs MergeMap?
Choosing between forkJoin and mergeMap depends on your specific use case:
Use forkJoin When:
You need to wait for multiple asynchronous operations to complete before proceeding (like HTTP requests).
You want to combine results from multiple observables and get the results only after all observables have emitted their last value.
You don’t need intermediate results, only the final outcome when all observables are completed.
Use mergeMap When:
You need to transform each emitted value into a new observable and flatten the results.
You want to handle multiple asynchronous operations concurrently, without waiting for one to complete before starting the next.
You are dealing with a stream of events that require an asynchronous operation for each emitted value.
Conclusion
Both forkJoin and mergeMap are crucial operators in RxJS that empower Angular developers to work efficiently with asynchronous operations. By understanding their behaviors and choosing the right one for the task at hand, you can build more robust and performant applications.
Whether you are combining multiple HTTP requests using forkJoin or transforming a stream of events using mergeMap, both tools allow you to handle concurrency in a clean, maintainable manner, ultimately enhancing the user experience.


