1

I want to achieve the following in angular 6:

while(true) {

  • call API
  • process the response
  • wait 1 second

}

I tried the TimerObservable, but failed to make wait 1 second after the request has finished because it is asynchronous. The purpose is to not call the api when requests take a long time but to have the latests response quick when requests take short time to finish.

My Code is:

TimerObservable.create(0, 1000)
  .subscribe(() => {
    this.api.getData().subscribe(
      response => {
        console.log(response);
      }
    );
  });
Sebastian Viereck
  • 5,455
  • 53
  • 53
  • Possible duplicate of [Repeat request (Angular2 - http.get) n seconds after finished](https://stackoverflow.com/questions/37938735/repeat-request-angular2-http-get-n-seconds-after-finished) – David Walschots Aug 30 '18 at 09:33

3 Answers3

3

You could always use recursion for this. Put the call within a function, and on success, wait 1 second, and then call the function again.

callApi() {
  this.api.getData().subscribe(
    response => {
      console.log(response);
      setTimeout(() => this.callApi(), 1000);
    }
  );
}

Bear in mind, this code will stop if there is a failure, so you may want to add an error handler in as well. You may want to wait longer if there is an error for example

user184994
  • 17,791
  • 1
  • 46
  • 52
1

You should use the exhaustMap (see doc here) operator to transform your "intervaled" tick into an api call. ExhaustMap will wait for the API call completion before launching a new one.

Try this (rxjs 6 syntax) :

import { interval, of } from 'rxjs';
import { exhaustMap } from 'rxjs/operators';

interval(1000)
.pipe(
    exhaustMap(_ => this.api.getData())
)
.subscribe(response => console.log(response));
Pierre Mallet
  • 7,053
  • 2
  • 19
  • 30
  • Though as far as I understand this won't wait for 1 second after each HTTP call, but instead will ignore interval emitted values until the HTTP call has finished and then do another call on the next emission, which might be anywhere between 0 and 1000ms in the future. – David Walschots Aug 30 '18 at 09:54
  • @DavidWalschots yes you are right. But i think it will do the job :D – Pierre Mallet Aug 30 '18 at 10:47
0

It's a bit clumsy but if you want to always first process the response and then wait I don't know of any easier way to do it.

Observable.timer(0, 1000)
  .concatMap(() => mockApiGetData()
    .concatMap(val => Observable.of(null)
      .delay(1000)
      .takeWhile(() => false)
      .startWith(val)
    )
  )
  .subscribe(val => console.log('process', val))

Live demo: https://stackblitz.com/edit/typescript-lemfdn?file=index.ts

See also: Observable and how to control results pace

martin
  • 93,354
  • 25
  • 191
  • 226