简体   繁体   中英

RxJs - (why) Does an Observable emit it's latest value on a new subsription?

Ok, this is a quick one, i'm kinda exhausted already and am confusing myself :D

I'm working with angular2 and RxJS Observables.

I have a service with a property "data", which is an Observable that get's set in the constructor, and a method to return this observable to subscribe to.

export class test{
    private data: Observable<Object>
    constructor(private http: Http){
       this.data = this.http.get(url).map( res => res.json());
    }  
    getData(): Observable<Object>{
       return this.data
    }
}

I have worked wit replaySubjects a while ago to always emit all values of the sequence to new subscribers. However, with the code above the Observable seems to emit it's latest value to new subscribers. Is this intended?

test(i: number) {
      if (i > 0) {
        setTimeout( () => {
          this.dataService.getData().subscribe( (data) => {
            this.debug.log(data);
            this.test(i-1);
          });
        }, 2000);
      }
    }
test(4)

I get a value for every iteration. I am confused, 'cause a year ago when i wanted that behaviour, i got no new values when subscribing 'too late'. Essentially, i just want to cache the result of the http.get, and deliver the same value to all subscribers, instead of making a new http request for every subscription (returning the http.get(url).. in getData())

I know this question is a bit old, but the answers seem to me quite confusing.

The Observable you return from the method getData() is just that, an Observable. So every time a consumer subscribes it gets the response. So it is working fine, but it is indeed making a new request every time.

In order to cache the result there are plenty of ways to do it depending on the behavior you want. To just cache a single request I would recommend t use the #publishBehavior operator:

export class test{
  private data: Observable<Object>;
  constructor(private http: Http){
    this.data = this.http.get(url)
      .map(res => res.json())
      .publishBehavior([])
      .refCount();
  }  
  getData(): Observable<Object>{
    return this.data;
  }
}

The parameter passed to the publishBehavior is the initial value. With this two operators, the request will be made when the first subscriber arrived. Next subscribers will get the cached answer.

In others answers the use of Subjects has been suggested. The publishBehavior is using subjects under the hood. But to directly call next() it is consider bad practice unless there is no other remedy, and thats not the case for this scenario in my opinion. Even if you use Subjects directly, it will be wise to return an Observable to the Components by using the #asObservable() operator so the component won't have access to the next, error and complete methods.

No. You need to use Subject for this. It has a method next() to which you will send your newly arrived property so that it pushes it to the subscribers.

In addition to this, you should create a service that will be a singleton. Whenever your components instantiate it in a constructor, they will receive the object already formed with all the data. There will be no need to fetch the data every time.

Also, instead of instantiating your data in the constructor, implement OnInit and do the calls to the server from there.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM