Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rxjs: perform some action regulary with specific delay in between

Client applications sends request to server, that could potentially take long to complete. Once request is finished or failed, client should wait some period of time (i.e. 10 seconds) and then again send the request.

Current working solution is this:

appRequest = new Subject();

ngOnInit(): void {
  this.appRequest.delay(10000).subscribe(() => this.refresh());
  this.refresh();
}

refresh() {
  this.api.getApplications().subscribe(a => {
      this.updateApplications(a);
      this.appRequest.next();
    },() => this.appRequest.next()
  );
}

Is there a more elegant solution for this?

EDIT:

I could use timer with regular intervals but I don't want to send new request unless previous request has finished. Only after previous request has finished, I want to wait 10 seconds and do send request again. This should repeat indefinitely.

getApplications() function is generated by swagger and it internally uses angular's http client library. Current observation is that unless you subscribe to Observable returned by getApplications(), it will not send request to server.

like image 408
Sasa Avatar asked Jan 12 '18 10:01

Sasa


Video Answer


1 Answers

The repeatWhen() operator seems designed for this, but there is a lack of examples and docs in the rxjs flavor.

Here's a doc for RxJava (description also applies to RxJs) RxJava's repeatWhen and retryWhen, explained.

Uses
Poll for data periodically using repeatWhen + delay:
source.repeatWhen(completed => completed.delay(5000))

Your version might be

stopRequesting = new Subject();

ngOnInit() {
  this.api.getApplications()
    .repeatWhen(completed => completed.delay(10000))
    .takeUntil(stopRequesting)
    .subscribe(a => this.updateApplications(a))
} 

ngOnDestroy() {
  this.stopRequesting.next(true);
}

Demo

// log to html output
log = function(x) { document.write(x + "<br />"); };

const stop = new Rx.Subject();

Rx.Observable.interval(500)
  .take(2)
  .repeatWhen(completed => completed.delay(1000))
  .takeUntil(stop)
  .subscribe(
    x => log(`Next: ${x}`),
    err => log(`Error: ${err}`),
    () => log('Completed')
  );

setTimeout(() => stop.next(true), 10000)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.js"></script>
like image 73
Richard Matsen Avatar answered Sep 22 '22 19:09

Richard Matsen