2016-04-19 6 views
2

Ich muss das Ergebnis einer Anfrage beim ersten Anruf zwischenspeichern und dann den zwischengespeicherten Wert für nachfolgende Anrufe lesen.Wie können Funktionsaufrufe mit RXJS dynamisch verkettet werden?

Um dieses Ziel zu erreichen, verwende ich Versprechungen und ich verkette sie. Ich habe eine funktionierende Lösung, aber ich würde es gerne in RxJS Observables statt Promises konvertieren.

Hier ist meine Arbeitslösung:

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

Sie können es auf dieser plunkr testen: https://plnkr.co/edit/j1pm2GeQf6oZwRvbUsXJ?p=preview

Wie erreiche ich das Gleiche mit RxJS 5 Beta?

aktualisieren

Bergi Kommentare Nach ich meine plunkr und meinen Code aktualisiert es näher zu bringen meine realen Fall

+0

„*' neue Promise ((r) => this.currentPromise.then (() => this._getSomething (params) .then ((res) => r (res)))); '*" - was? Was soll das tun (und: [tue es nicht] (http://stackoverflow.com/q/23803743/1048572))? Warum nicht einfach die 'currentPromise' zurückgeben? – Bergi

+0

Wenn Sie bereits 'currentPromise' zwischenspeichern, müssen Sie den Wert nicht zusätzlich in' .cache' zwischenspeichern. Übertreibe es nicht. – Bergi

+0

@Bergi Jedes Mal, wenn "getSomething" aufgerufen wird, füge ich ein neues ".then()" an das currentPromise an, so dass alle "getSomething" -Aufrufe in derselben Reihenfolge ausgeführt werden, in der sie aufgerufen werden. Der erste Aufruf ruft die Daten vom Server ab und speichert sie zwischen. Die nachfolgenden Aufrufe geben die Daten aus dem Cache zurück. –

Antwort

1

AsyncSubjects sind die Rx-Analogon von Versprechungen. publishLast ist der beste Weg, um aus einem Observablen einen zu machen. So etwas sollte funktionieren:

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

Danke Das ist sehr nützlich, ich weiß, dass ich das nicht in meine Frage aufgenommen habe, aber wie würdest du mit dem Fall umgehen, wo "getSomething" eine Reihe von Dingen erhalten kann, die man in Parameter bekommen kann. Beispiel: getSomething (["thing1", " dings2 "]) würde beide vom Server bekommen dann getSomething ([" thing1 "," thing3 "]) würde thing1 vom Cache und ding3 vom Server zurückgeben. –

+0

was würden Sie erwarten, dass das Observable erzeugt? Eine Reihe von Ergebnissen? – Brandon

+0

Genau. Ich bin mir nicht sicher, wie es funktionieren würde, aber ich denke, es würde die nächste() verwenden, um das "t" zu aggregieren hings "in einem Array dann rufen Sie die komplette() -Funktion, um den Abonnenten auslösen, wenn sie bereit sind. –

Verwandte Themen