IMO, it's better to handle the polling either through Promises or RxJS without mixing them. I'd illustrate using RxJS.
Try the following
- Convert the promise to an observable using the RxJS
from
function.
- Use RxJS functions like
timer
or interval
to regularly emit a value on a fixed interval.
- Use a higher order mapping operator like
switchMap
to map from the outer emission to your API call. Refer here for a brief description about different types of higher order mapping operators.
- Use two
takeWhile
operators, one for each of your condition respectively, to complete the subscription.
- Use
filter
operator to only forward the emissions that pass the condition.
import { from } from 'rxjs';
fetchData(id: any): Observable<any> { // <-- return an observable
return from(apiCall); // <-- use `from` to convert Promise to Observable
}
import { timer } from 'rxjs';
import { filter, switchMap, takeWhile } from 'rxjs/operators';
timer(0, 5000).pipe( // <-- poll every 5 seconds
takeWhile((index: number) => index < 20) // <-- stop polling after 20 attempts
switchMap((index: number) =>
this.someService.apiCall(index+1) // <-- first emission from `timer` is 0
),
takeWhile( // <-- stop polling when a condition from the response is unmet
(response: any) => response.someValue !== someOtherValue,
true // <-- emit the response that failed the test
),
filter((response: any) =>
response.someValue === someOtherValue // <-- forward only emissions that pass the condition
)
).subscribe({
next: (response: any) => {
// handle response
},
error: (error: any) => {
// handle error
}
});
Edit: The condition in the 2nd takeWhile
was doing the opposite of the requirement. I've adjusted the condition and included the inclusive=true
argument. Thanks @Siddhant in the comments.