2016-02-27 14 views
11

ja stworzyliśmy usługę, która sprawia, że ​​prosty wniosek otrzymujemy:żądania HTTP wykonane kilka razy w Angular2 usługi

private accountObservable = null; 

constructor(private _http: Http) { 
} 

getAccount() { 
    // If we have account cached, use it instead 
    if (this.accountObservable === null) { 
     this.accountObservable = this._http.get('http://localhost/api/account') 
      .map(res => <Account> res.json().data) 
      .catch(this.handleError); 
    } 

    return this.accountObservable; 
} 

Dodałem, że usługa w mojej funkcji bootstrap świadczenia globalnie (mam nadzieję, aby zapewnić to samo wystąpienie dla wszystkich składników):

provide(AccountService, { useClass: AccountService }) 

Problem polega na tym, że wywołuję tę usługę w różnych komponentach, żądanie GET jest wykonywane za każdym razem. Jeśli dodaję go do 3 komponentów, zostaną wysłane 3 żądania GET, mimo że sprawdzam, czy obserwowalne już istnieją.

ngOnInit() { 
    this._accountService.getAccount().subscribe(
    account => this.account = account, 
    error => this.errorMessage = <any>error 
); 
} 

Jak mogę zapobiec wielokrotnemu zgłoszeniu żądania GET?

+1

Czy tylko "dostarczasz usługę na poziomie bootstrap? (Wygląda na to, że możesz umieścić go w tablicy 'provider' we wszystkich komponentach, co utworzyłoby 3 instancje twojej usługi). Jeśli udostępniasz go tylko na poziomie bootstrap, spróbuj użyć [Observable.share()] (https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/share.md) . (Są to po prostu domysły z mojej strony.) –

+1

Zobacz także http://stackoverflow.com/a/35527616/215945 dla nieco innej implementacji buforowania wyniku serwera. –

+1

Tak, tylko 'dostarczam' na bootstrap. Próbowałem dodać console.log() w konstrukcji usługi i jest ona uruchamiana tylko raz. Dodałem 'share()' po 'get()', ale nie robiło to różnicy. Drugi post też nie działał. Chyba dlatego, że dopóki nie otrzymamy danych, zostanie wysłane nowe żądanie. Jeśli więc 3 składniki działają w tym samym czasie, getAccount(), wszystkie będą wysyłać żądania i nie zatrzymają się, dopóki jedna z nich nie otrzyma odpowiedzi. – Christoffer

Odpowiedz

19

Korzystanie Observable.share():

if (this.accountObservable === null) { 
    this.accountObservable = this._http.get('./data/data.json') 
     .share() 
     .map(res => res.json()) 
     .catch(this.handleError); 
} 

Plunker

W Plunker, AppComponent i Component2 oba wywołania getAccount().subscribe() dwa razy.

Na karcie Sieć narzędzia Narzędzia dla deweloperów Chrome jest wyświetlane jedno żądanie HTTP dla data.json. Z komentarzem share() są 4 żądania.

+6

To nie działa.Widziałem ten problem jakiś czas temu, a to rozwiązanie, widząc to znowu, rozwiązanie wciąż nie działa. –

+0

Nie zapomnij również dodać 'import 'rxjs/add/operator/share';' @ RickO'Shea Ta odpowiedź działa doskonale. Jeśli to nie działa, możesz opublikować plunkr, który pokazuje, że masz z tym problem. – jlh

2

Istnieją dwa rodzaje obserwowalnych obiektów.

Zimna Obserwowalne: każdy abonent otrzyma wszystkie zdarzenia (od początku)

Hot obserwowalne: każdy abonent odbierać zdarzenia, które są emitowane po subskrypcji.

Cold Observables są domyślne. Właśnie to wywołanie WS jest uruchamiane wiele razy.

Aby obserwowalnych Hot trzeba użyć następujących RX operatorów sieci:

.publish().refCount() 

W twoim przypadku:

getAccount() { 

    let accountObservable = this._http.get('http://localhost/api/account') 
      .map(res => <Account> res.json().data) 
      .catch(this.handleError); 

    return accountObservable.publish().refCount(); 
} 
+1

Ale czy to nie będzie nadal powodować żądanie HTTP za każdym razem, gdy zostanie wywołana funkcja 'getAccount()'? –

+1

Wystąpił błąd "Publikacja właściwości" nie istnieje w typie "Observable ". " –

Powiązane problemy