2017-02-09 3 views
7

In meiner Angular 2 App muss ich eine Reihe von HTTP-Anfrage machen. Ich habe zwei Dienste, A & B, die jede Anfrage machen, A.get() und B.get(), die Daten von der API erhält und sie in ihrem Dienst speichert. Diese zwei können gleichzeitig aufgerufen werden, aber ich habe eine dritte Anfrage doSomething(), die von den Ergebnissen A.get() und B.get() abhängt. Da sowohl A.get() als auch B.get() ihre Antworten lokal speichern, endet ihr Rückgabewert mit dem RxJs-Abonnement. Wie so:Warte auf RxJs.Subscriptions zu beenden, bevor wieder

class A{ 
    public data; 
    public get(){ 
    return api.call(params).subscribe((response)=>{ this.data = response.json();}) 
    } 
} 

class B{ 
    public data; 
    public get(){ 
    return api.call(params).subscribe((response)=>{ this.data = response.json();}) 
    } 
} 

Meine Komponente etwa wie folgt aussieht:

class MyComponent{ 
    constructor(private a: A, private b: B){ 
    a.get(); 
    b.get(); 
    this.doSomething(a.data, b.data); 
    } 
    doSomething(aData, bData){ 
    ... 
    } 
} 

Mein Problem ist doSomething() versagt, weil a.get() und b.get() haben noch dort HTTP-Anforderung abgeschlossen. Ich brauche einen Weg, um doSomething() zu halten, bis meine anderen Anrufe abgeschlossen sind. Ich habe überall gesucht, aber ich hatte kein Glück mit diesem Problem. RxJs Dokumentation gibt ein paar Möglichkeiten, wie Sie Observables zusammenführen können, aber das ist nicht, was ich in diesem Fall habe.

Antwort

5

Nun, was Sie wollen, können mit diesem erreicht werden:

class A { 

    private data; 

    public get(): Observable<any> { 
     // this is a very primitive caching just to show concept 
     if (this.data) { 
      return Observable.of(this.data); 
     } 
     // In real life it would be something like this: 
     // let call = this.http.get(...).map(r => r.json()) 
     let call = Observable.of("some value A"); 
     return call.do(s => this.data = s); 
    } 

} 

class B { 

    private data; 

    public get(): Observable<any> { 
     if (this.data) { 
      return Observable.of(this.data); 
     } 
     let call = Observable.of("some value B"); 
     return call.do(s => this.data = s); 
    } 

} 

class MyComponent { 
    constructor(private a: A, private b: B) { 
     Observable 
      .zip(this.a.get(), this.b.get(), (a: any, b: any) => { return { a: a, b: b } }) 
      .subscribe((r) => { 
       this.doSomething(r.a, r.b); 
      }); 
    } 
    doSomething(aData, bData) { 
     console.log("aData", aData); 
     console.log("bData", bData); 
    } 
} 

Dies ist eine Modifikation des Codes. Wie Sie sehen, brauchen Sie keine Observablen innerhalb der Servicekomponenten zu abonnieren. Es ist nicht einmal notwendig, sie separat außerhalb der Servicekomponenten zu abonnieren. Wir können das Endergebnis in der einzigen endgültigen Subskription() direkt erhalten, indem wir Observable auf eine bestimmte Art kombinieren.

UPDATE

Was ist der Unterschied zwischen do ist() und subscribe().

Vereinfacht ein Bit (überspringbare Observables), wird beobachtbare Pipe nichts anfangen, bis Sie es abonnieren. do() ist nur einer von vielen Operatoren, die entworfen wurden, um einige "Nebenwirkungen" in der Kette Ihrer Observablen zu haben, zum Beispiel kann sie einige Zwischenergebnisse in der Mitte beobachtbarer Pipe ausgeben, um sie zu Debugging-Zwecken zu trösten. Dies ist der Hauptunterschied. Also, Sie können etwas in subscribe() ohne do() in der Mitte bekommen, aber Sie bekommen nichts in do() ohne subscribe().

+0

Dank aufgerufen @ Alexander, das hat super funktioniert! Eine Folgefrage, was ist der Unterschied zwischen .do und .subscribe. Verliere ich irgendeine Funktionalität, indem ich .do auf dem Observable anrufe? – tanspac

+0

Ich bekomme diesen Teil nicht: if (this.data) { return Observable.of (this.data); } – user2243952

0

Verwenden Sie Observable.forkJoin, um Ihr Problem zu lösen, indem Sie Ihr Abonnement auf die Komponente verschieben. Es dauert eine Reihe von kalten Observablen, und nach dem Abonnieren erhalten Sie eine Reihe von Ergebnissen. Etwas wie folgt aus:.

Observable.forkJoin([ 
    a.get(), 
    b.get() 
]).subscribe(
    results => { 
     doSomething(results[0], results[1]); 
    }, 
    err => { 
     //handle error 
    } 
); 

Der Rückruf im Abonnement wird erst beide Anfragen kommen in gecallt

Wenn entweder a.get() oder b.get() ausfällt, wird die Error-Methode

Verwandte Themen