问题
I want to make several HTTP calls sequentially and after each call, I want to examine the result and make another call and display message, etc. In some cases continue to the next call, some cases break on that call after displaying message. On the other hand, I also need to use catchError
block of each call (or maybe a single block for all of them, but using one for each call would be better).
So, assume that I have an create, update and delete calls as shown below. How can I get each of these call's response and check the response and then execute another call?
I have tried switchMap
and iif
and I am looking a solution using one of them. Any suggestion?
this.service.create('/api/employee').subscribe(resp1 => {
this.service.update('/api/salary/', id).subscribe(resp2 => {
this.service.delete('/api/education/', id).subscribe(resp3 => {
// I need to get response of each call from starting thr first and then continue of
// break according to the condition of the response
});
});
回答1:
Using switchMap
here is a good approach:
this.service.create('/api/employee')
.pipe(switchMap((resp) => {
if(fulfillsCondition(resp)) {
return this.service.update(...);
}
return this.service.delete(...);
})).subscribe();
回答2:
I'm not sure there's much else to say here.
Of note, perhaps, is that EMPTY
is an RxJs stream that emits nothing and completes immediately. It is sort of like "break" (in a pretty loose way. How you "break" from a stream can be pretty context dependant).
this.service.create('/api/employee').pipe(
catchError(err1 => {
// do some stuff
return throwError(err1);
}),
switchMap(resp1 => {
// do some stuffs
if(someCondition(resp1)){
return this.service.update('/api/salary/', id).pipe(
catchError(err2 => {
// do some stuff
return throwError(err2);
}),
);
}
return EMPTY;
}),
switchMap(resp2 => {
// do some stuff
if(someCondition(resp2)){
return this.service.delete('/api/education/', id).pipe(
catchError(err3 => {
// do some stuff
return throwError(err3);
}),
);
}
return EMPTY;
}),
).subscribe({
next: resp3 => { /*do some stuff*/ },
complete: () => { /*Your stream is done*/ },
eror: err => { /*All re-thrown errors end up here */ }
});
Update
Using tap
to help understand streams
tap
is an operator that returns the same stream that it receives. It can't make any changes to your stream, but it can look at what is happening at any given point. This can be a useful tool to aid your understanding.
http1().pipe(
tap({
next: val => console.log("Result from http1 call: ", val),
complete: () => console.log("http1 call completed"),
error: err => console.log("http1 call errored: ", err)
})
switchMap(val => http2(val).pipe(
tap({
next: val => console.log("Result from http2 call: ", val),
complete: () => console.log("http2 completed"),
error: err => console.log("http2 call errored: ", err)
})
)),
tap({
next: val => console.log("Result from switchMap operator: ", val),
complete: () => console.log("switchMap completed"),
error: err => console.log("switchMap (http1 or http2 call) errored: ", err)
})
).subscribe()
Here we can see what is happening before and after the switchMap
. You can see that in this case, switchMap is taking a value from http1 and emitting the values from http2.
Because switchMap waits for values from http1 before generating http2, one side effect is that http2 doesn't start until after http1 emits. This does mean that these calls are executed sequentially, but the story gets more complicated if http1 emits more than once.
More About:
- switchMap
- concatMap
- mergeMap
来源:https://stackoverflow.com/questions/64858071/how-to-execute-and-get-result-of-sequential-http-calls-using-rxjs