2017-02-09 6 views
7

W mojej aplikacji Angular 2 muszę wykonać serię żądań http. Mam dwie usługi: A & B, każda z nich, A.get() i B.get(), która pobiera dane z interfejsu API i przechowuje je w ich usłudze. Te dwa mogą być wywoływane w tym samym czasie, jednak mam trzecie żądanie doSomething(), które zależy od wyników A.get() i B.get(). Ponieważ zarówno A.get() jak i B.get() przechowują swoje odpowiedzi lokalnie, ich wartością powrotną jest Subskrypcja RxJ. Tak:Poczekaj na RxJs.Subscriptions, aby zakończyć przed wznowieniem

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

Moja komponent wygląda mniej więcej tak:

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

Mój problem jest doSomething() się niepowodzeniem, ponieważ a.get() i b.get() ukończyli jeszcze tam żądania HTTP. Potrzebuję sposobu, aby zadzwonić pod numer doSomething(), dopóki moje pozostałe połączenia nie zostaną zakończone. Przeszukałem wszystko, ale nie miałem szczęścia z tym problemem. Dokumentacja RxJs daje kilka sposobów na scalenie Observables, ale to nie jest to, co mam w tym przypadku.

Odpowiedz

5

No, co chcesz można osiągnąć w ten sposób:

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

Jest to modyfikacja kodu. Jak widać, nie ma potrzeby subskrybowania obserwowalnych elementów usługi. Nie ma nawet potrzeby subskrybowania ich oddzielnie poza komponentami usługi. Możemy bezpośrednio otrzymać ostateczny wynik w pojedynczym finalnym subskrybowaniu() tylko poprzez połączenie obserwowalnych w określony sposób.

UPDATE

Jaka jest różnica między zrobienia() i zapisać się().

Upraszczając nieco (pomijając gorące obserwowalne), obserwowalna rura nie zacznie niczego robić dopóki nie zasubskrybujesz. do() jest tylko jednym z wielu operatorów zaprojektowanych, aby mieć pewne "efekty uboczne" w łańcuchu twoich obserwowalnych obiektów, na przykład może wyprowadzać pewne pośrednie wyniki w środku obserwowalnej rury do konsoli dla celów debugowania. To główna różnica. Tak, możesz dostać coś w subskrybować() bez do() w środku, ale nie dostaniesz niczego w do() bez subskrybowania().

+0

Dzięki @ Alexander, który działał świetnie !. Jedno pytanie uzupełniające, jaka jest różnica między .do a .subscribe. Czy tracę jakąkolwiek funkcjonalność, dzwoniąc do .do na Observable? – tanspac

+0

Nie otrzymuję tej części: if (this.data) { return Observable.of (this.data); } – user2243952

0

Użyj Observable.forkJoin, aby łatwo rozwiązać problem, przenosząc subskrypcję do komponentu. Zajmuje całą gamę obserwatorów zimnych, a po subskrybowaniu otrzymuje tablicę wyników. Coś takiego:.

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

Wywołanie zwrotne w subskrypcji nie będzie sprawdzony aż oba wnioski pochodzą w

Jeśli któryś a.get() lub b.get() zawiedzie metoda błąd zostanie sprawdzony