Currently, I am deepening my understanding of rxjs and struggling to find an efficient way to manage a sequence of requests. For instance, let's consider the UserService
where one of its functions retrieves a user object based on the user id. After obtaining this object, I want to utilize its data to make multiple post requests in the following manner:
this.userService.getUser(5).subscribe(
user => this.userService.sendEmail(this.makeEmailMessage(user.id, user.name, user.email)).pipe(
delay(1000),
tap(() => console.log('Sending an email'))
).subscribe(
() => this.userService.sendSMS(this.makeSMSMessage(user.id, user.name, user.phone)).subscribe(
() => console.log('Sending sms')
)
)
);
However, nesting subscribes like this can quickly lead to code that is difficult to follow and manage, especially when additional requests are involved.
A more structured approach would be to rewrite the above code as shown below:
this.userService.getUser(5).pipe(
switchMap(
user => {
return forkJoin(
this.userService.sendEmail(this.makeEmailMessage(user.id, user.name, user.email)).pipe(
delay(1000),
tap(() => console.log('Sending an email.'))
),
this.userService.sendSMS(this.makeSMSMessage(user.id, user.name, user.phone)).pipe(
tap(() => console.log('Sending an sms'))
)
);
}
)
).subscribe(
res => console.log(res)
);
Using the forkJoin
operator maintains the order of requests, even though the SMS request may finish first. If request order is important, then this code suffices, but what if preserving order is mandatory?
My main query pertains to the best practices for handling scenarios where request order matters versus situations where it doesn't. Additionally, in terms of error management, is it appropriate to handle errors using the catchError
operator within the pipes (where tap
was used)?