Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Start first call of IntervalObservable instant

I'm using an IntervalObservable to make continuous calls to the server side of my application. I can subscribe and unsubscribe to to the Oberservable and everything works fine with one exception:

The first call to the server is delayed, but I want it to be instant. The behaviour of the IntervalObservable is in principle correct, but does not match my requirements.

@Injectable()
export class LoggerService {
  constructor(private http: Http) { }
  private apiURL = 'assets/file.json'; 

  getList() {
       return IntervalObservable.create(1000).flatMap(() 
       => this.http.get(this.apiURL))
      .map(this.extractData)
      .catch(this.handleError);
  }
  private extractData(res: Response) {
    var fooot = new Foo();
    fooot.fillFromJSON(JSON.stringify(res.json()));
    return fooot;
  }

  private handleError(error: any) {
    let errMsg = (error.message) ? error.message :
      error.status ? `${error.status} - ${error.statusText}` : 'Server error';
    console.error(errMsg);
    return IntervalObservable.throw(errMsg);
  }
}

So how can I call the server instant on the first call and afterwards with the defined delay?

like image 330
Akkusativobjekt Avatar asked Oct 12 '16 08:10

Akkusativobjekt


4 Answers

Two things,

  1. You can use the factory methods instead of the derived types, i.e. Observable.interval(3000) instead of IntervalObservable.create
  2. You can use timer to do it with a single operator instead:

    return Observable.timer(0, 1000)
      .flatMapTo(this.http.get(this.apiURL))
      .map(this.extractData)
      .catch(this.handleError);
    
like image 61
paulpdaniels Avatar answered Oct 26 '22 07:10

paulpdaniels


You can use startWith.

Following example pushes an event on the stream when it is created:

 getList() {
    return IntervalObservable.create(1000)
     .startWith(1) // needs a value, but won't be used
     .flatMap(() => this.http.get(this.apiURL))
     .map(this.extractData)
     .catch(this.handleError);  
 }
like image 32
mahulst Avatar answered Oct 26 '22 08:10

mahulst


I'd use concat and concatMap for this:

See live demo: http://plnkr.co/edit/4kdJRD7HZqrbce7MFPW7

import {Observable} from 'rxjs';

let httpRequest = () => Observable.of('response');

Observable.of(null)
  .concat(Observable.interval(3000))
  .concatMap(httpRequest)
  .subscribe((response) => console.log(response));

The first request is triggered with Observable.of(null) which goes through the operator chain and triggers httpRequest. Then it's all up to the Observable.interval operator.

like image 22
martin Avatar answered Oct 26 '22 06:10

martin


For #RxJS Version 5+ :

You can use rxjs interval operator and implement polling. The following implemention will execute the this.statusService.getStatus() line in every 1000 ms interval :

 getList() {
     return Observable.interval(1000).startWith(1)
     .mergeMapTo(this.http.get(this.apiURL))
     .catch(this.handleError);
}

With startWith(1) added, now, it will be immediately executed without any delay and after that it will be executed every 1 sec interval. I think this is what you want.

Or Another approach: you can use timer operator and do the following:

getList() {
    return Observable.timer(0, 1000)
      .mergeMapTo(this.http.get(this.apiURL))
      .catch(this.handleError);
}

In this approach, the timer operator will instantly execute and after that it will execute in every 1000 ms.

Also don't forget to import :

  import {Observable} from 'rxjs/Observable';
  import 'rxjs/add/operator/startWith';
  import 'rxjs/add/operator/mergeMapTo';
  import 'rxjs/add/observable/timer';
like image 31
asmmahmud Avatar answered Oct 26 '22 07:10

asmmahmud