Objective :
- To call an Api repetitively at defined intervals(delay/gap).
- We want to fetch the data when the previous request has finished.
- If previous request fails, we still want to retry 2/3 time (n number of times)
Problem with other given solutions:
All given answers are solving the first objective. BUT NOT THE REST. In a real world scenario we don't want to burden the server (server might take 3-4 seconds to respond but we still call api at fixed interval which is bad ) and we also want to write defensive code on frontend ( if server fails to respond , we still want to retry).
Solution:
Here is the complete working code
import { of, concat, Observable, BehaviorSubject } from 'rxjs';
import { delay, tap, skip, concatMap, map, retry } from 'rxjs/operators';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-comp',
template: ` <div>{{polledApi$ | async}}</div> `,
styleUrls: ['./comp.component.scss']
})
export class CompComponent implements OnInit {
api$ = this.http.get('https://blockchain.info/ticker');
load$ = new BehaviorSubject('');
polledApi$: Observable<number>;
restart$ = of('').pipe(
delay(5000), // wait for 5sec
tap(_ => this.load$.next('')), // calls load$
skip(1),
);
constructor(private http: HttpClient) { }
ngOnInit(): void {
this.polledApi$ = this.load$.pipe(
concatMap(_ => concat(this.api$, this.restart$)), // restart only when api gives response
map((response: any) => response.EUR.last), // Just a map operator for this example.
retry(3) // retry 3 times in case of error
);
}
}
Explanation:
Here we have 4 Observables
api$ It defines api endpoint.
load$ it is a BehaviourSubject which kind of glues all observables together.
restart$ used only to call load$ after 5sec delay. it itself don't do anything.
- polledApi$ The ACTUAL ONE which we subscribe to.
A complete explanation of all operators like concat, tap might not be possible here.
This code covers around all practical issues regarding polling.