I need to cache the result of a request on the first call then read the cached value for subsequent calls.
To achieve that goal, I am using promises and I am chaining them. I have a working solution but I would like to convert it to RxJS's observables instead of Promises.
Here is my working solution:
private currentPromise: Promise<{ [key: string]: any }>;
private cache: any;
public getSomething(name: string): Promise<number>{
return this.currentPromise = !this.currentPromise ?
this._getSomething(name) :
new Promise((r) => this.currentPromise.then(() => this._getSomething(name).then((res) => r(res))));
}
private _getSomething(name: string): Promise<any> {
return new Promise((resolve) => {
if (this.cache[name]) {
this.messages.push("Resolved from cache");
resolve(this.cache[name]);
} else {
// Fake http call. I would use Angular's Http class.
setTimeout(()=> {this.messages.push("Resolved from server"); this.cache[name] = name; resolve(this.cache[name]); }, 2000 );
}
});
}
this.getSomething("thing1").then((res)=>this.messages.push(res));
this.getSomething("thing1").then((res)=>this.messages.push(res));
this.getSomething("thing2").then((res)=>this.messages.push(res));
this.getSomething("thing2").then((res)=>this.messages.push(res));
this.getSomething("thing1").then((res)=>this.messages.push(res));
this.getSomething("thing2").then((res)=>this.messages.push(res));
this.getSomething("thing1").then((res)=>this.messages.push(res));
this.getSomething("thing2").then((res)=>this.messages.push(res));
You can test it on this plunkr: https://plnkr.co/edit/j1pm2GeQf6oZwRvbUsXJ?p=preview
How do I achieve the same thing with RxJS 5 beta?
Update
Following Bergi's comments I updated my plunkr and my code to bring it closer to my real case
AsyncSubjects are the Rx analog of Promises. publishLast is the best way to turn an observable into one. Something like this should work:
private cache: {string: Rx.Observable<any>};
public getSomethings(names: string[]) : Rx.Observable<any> {
// call getSomething for each entry in names
// streams is an array of observables
const streams = names.map(name => this.getSomething(name));
// transform streams into an observable with an array of results
return Observable.zip(streams);
}
public getSomething(name: string) : Rx.Observable<any> {
if (!this.cache[name]) {
// create the request observable
// const request = Rx.Observable.ajax(...); // http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#static-method-ajax
// for now, just wait 2 seconds and return name
const request = Rx.Obsevable.of(name).delay(2000);
// use "do" to log whenever this raw request produces data
const loggedRequest = request.do(v => this.messages.push("retrieved from server " + v));
// create an observable that caches the result
// in an asyncSubject
const cachedRequest = loggedRequest.publishLast();
// store this in our cache object
this.cache[name] = cachedRequest;
}
// return the cached async subject
return this.cache[name];
}
// usage
this.getSomething("thing1").subscribe(v => this.messages.push("received " + v));
this.getSomething("thing1").subscribe(v => this.messages.push("received " + v));
this.getSomething("thing1").subscribe(v => this.messages.push("received " + v));
this.getSomething("thing1").subscribe(v => this.messages.push("received " + v));
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.