2016-02-27 7 views
11

ho creato un servizio che rende una semplice richiesta GET:richiesta HTTP effettuata più volte in servizio Angular2

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

ho aggiunto che il servizio nella mia funzione di bootstrap per fornire a livello globale (la mia speranza è di fornire al stessa istanza a tutti i componenti):

provide(AccountService, { useClass: AccountService }) 

Il problema è quando chiamo questo servizio in diversi componenti, una richiesta GET viene effettuata ogni volta. Quindi, se lo aggiungo a 3 componenti, verranno fatte 3 richieste GET anche se controllo se esiste già un osservabile.

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

Come si può impedire che la richiesta GET venga eseguita più volte?

+1

Si sta solo fornendo il servizio a livello di bootstrap? (Sembra che potresti elencarlo nella matrice 'providers' in tutti i tuoi componenti, che creerebbe 3 istanze del tuo servizio). Se lo fornisci solo a livello di bootstrap, prova a utilizzare [Observable.share()] (https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/share.md) . (Queste sono tutte solo supposizioni da parte mia.) –

+1

Vedere anche http://stackoverflow.com/a/35527616/215945 per un'implementazione leggermente diversa della memorizzazione nella cache di un risultato del server. –

+1

Sì, ho solo 'fornire' su bootstrap. Ho provato ad aggiungere console.log() nel costrutto del servizio e viene attivato una sola volta. Ho aggiunto 'share()' dopo 'get()' ma non ha fatto alcuna differenza. Anche l'altro post non ha funzionato. Immagino sia perché finché non avremo ricevuto i dati, verrà fatta una nuova richiesta. Quindi se 3 componenti eseguono getAccount() allo stesso tempo, tutti eseguiranno le richieste e non si fermeranno finché uno di loro non avrà risposta. – Christoffer

risposta

19

Uso Observable.share():

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

Plunker

Nel Plunker, AppComponent e Component2 chiamano entrambi getAccount().subscribe() due volte.

Con share(), la scheda Rete degli strumenti per sviluppatori di Chrome mostra una richiesta HTTP per data.json. Con share() commentato, ci sono 4 richieste.

+6

Questo non funziona.Visto questo problema un po 'indietro, e questa soluzione, vedendolo di nuovo, soluzione ancora non funziona. –

+0

Inoltre, non dimenticare di aggiungere 'import' rxjs/add/operator/share '; '@ RickO'Shea Questa risposta funziona perfettamente. Se non funziona per te allora potresti voler postare un plunkr che mostri il tuo problema con esso. – jlh

2

Esistono due tipi di osservabili.

fredda osservabile: ogni abbonato riceve tutti gli eventi (dall inizio)

Hot osservabile: ogni abbonato di ricevere gli eventi che vengono emited dopo abbonamento.

Cold Observables sono quelli predefiniti. Questo è ciò che la chiamata WS viene attivata più volte.

Per effettuare una calda Observable è necessario utilizzare seguente catena di Rx operatori:

.publish().refCount() 

Nel tuo caso:

getAccount() { 

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

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

Ma questo non provocherà ancora una richiesta HTTP ogni volta che viene chiamato 'getAccount()'? –

+1

c'è un errore 'Proprietà 'pubblica' non esiste sul tipo 'Osservabile ' .' –