Reputation: 31
I've been searching for the right/best/correct way to chain a few Observable methods. I've read on the using pipe() and map() and so on, but i'm not 100% i fully understand. The basis is i have a few actions to carry out, which some needs to be in sequence, and some dont. Below are the 4 methods i need to call.
createOrder(order:Order):Observable<void>{
return new Observable((obs)=>
//Do Something
obs.complete();
)
}
updateCurrentStock(order:Order):Observable<void>{
return new Observable((obs)=>
//Do Something
obs.complete();
)
}
updateSalesSummary(order:Order):Observable<void>{
return new Observable((obs)=>
//Do Something
obs.complete();
)
}
updateAnotherDocument(order:Order):Observable<void>{
return new Observable((obs)=>
//Do Something
obs.complete();
)
}
From this 4, the flow should be createOrder
->updateCurrentStock
->updateSalesSummary, updateAnotherDocument
.
As of now, what i have is
var tasks = pipe(
flatMap(e => this.createOrder(order)),
flatMap(e => this.updateCurrentStock(order)),
flatMap(e => forkJoin([this.updateSalesSummary(order),this.updateAnotherDocument(order)])),
);
of(undefined).pipe(tasks).subscribe({
error: (err) => {
console.log(err);
obs.error(err);
},
complete: () => {
console.log('completed');
obs.complete();
}
});
It works, but i'm not sure if this is the right/cleanest way of doing it and if there is any possible issues in the future.
Upvotes: 2
Views: 1819
Reputation: 3723
There are a lot of rxjs operators, I recommend you read https://www.learnrxjs.io/learn-rxjs.
When you have an observable that depends on other's value use switchMap
Example:
const userId$: Observable<number>;
function getUserData$(userId: number): Observable<Data> {
// yourService.fetchUser(userId);
}
userId$.pipe(switchMap((userId: number) => getUserData$(userId)));
When you do not care about the order, you can use:
forkJoin
combineLatest
Example:
const userId$: Observable<number>;
function getUserAge$(userId: number): Observable<number> {
// ...
}
function getUserName$(userId: number): Observable<String> {
// ...
}
userId$.pipe(
switchMap((userId: number) =>
forkJoin([getUserAge$(userId), getUserName$(userId)])
)
);
In your case I think the order does not matter, as none of your observables needs data from the previous one. So I think you should use combineLatest
.
If the order of emission and subscription of inner observables is important, try concatMap
.
Upvotes: 1
Reputation: 8032
concat
concat will subscribe to your streams in order (not starting the next until the previous one completes.
This should be roughly equivalent.
One difference here is that unlike mergeMap
, you're not transforming the output of an api call, it still gets emitted. Since you're not doing anything with the next
callback in your subscription, it'll still look similar in the case.
concat(
this.createOrder(order),
this.updateCurrentStock(order),
forkJoin([
this.updateSalesSummary(order),
this.updateAnotherDocument(order)
])
).subscribe({
error: concosle.log,
complete: () => console.log('completed');
});
Here's how I would re-write your original code to be a bit easier to read.
this.createOrder(order).pipe(
mergeMap(_ => this.updateCurrentStock(order)),
mergeMap(_ => forkJoin([
this.updateSalesSummary(order),
this.updateAnotherDocument(order)
]),
).subscribe({
error: (err) => {
console.log(err);
obs.error(err); // <-- What's obs here?
},
complete: () => {
console.log('completed');
obs.complete();
}
});
Upvotes: 1