Start first call of IntervalObservable instant

与世无争的帅哥 提交于 2019-12-10 05:33:55

问题


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?


回答1:


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);
    



回答2:


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);  
 }



回答3:


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.




回答4:


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';


来源:https://stackoverflow.com/questions/39994096/start-first-call-of-intervalobservable-instant

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!