Angular 2 cache observável dados do resultado http

Eu tenho um serviço que busca dados através do serviço HTTP e retorna um object observável.

Após a primeira chamada, gostaria de armazenar em cache o resultado internamente no serviço e, assim que um novo componente tentasse obter os dados, ele o pegaria do resultado armazenado em cache.

Existe uma solução simples para isso?

Se você se inclinar para os observáveis ​​como um meio de compartilhar dados, você pode adotar a seguinte abordagem:

import { Injectable } from '@angular/core'; import { Http, Response } from '@angular/http'; import { Observable, ReplaySubject } from 'rxjs'; @Injectable() export class CachedService { data$: Observable = this.dataSubject.asObservable(); private dataSubject = new ReplaySubject(1); constructor(private http: Http) { } fetch() { this.http.get(...).subscribe(res => this.dataSubject.next(res)); } } 

Isso fará uma chamada HTTP quando o método de fetch for chamado e todos os assinantes de service.data$ receberão a resposta do ReplaySubject . Como ele reproduz valores anteriores, todos os assinantes que ingressarem após a chamada HTTP ainda receberão a resposta anterior.

Se você quiser acionar uma atualização, basta chamar service.fetch() para iniciar uma nova chamada HTTP e todos os assinantes serão atualizados assim que a nova resposta chegar.

Seus componentes seriam algo como:

 @Component({ ... }) export class SomeComponent implements OnInit { constructor(private service: CachedService) { } ngOnInit() { this.service.fetch(); this.service.data$.subscribe(...); } } 

Recentemente, escrevi um artigo no blog sobre essa abordagem para meus colegas: http://blog.jonrshar.pe/2017/Apr/09/async-angular-data.html

Eu acho que você não deve fazer um fetch () no construtor ou a qualquer momento no ciclo de vida de angular. E como você diz, ngOnInit não funciona em serviços angulares.

Em vez disso, queremos usar o rxjs para passar os valores armazenados em cache através do stream, sem que o chamador precise saber nada sobre valores armazenados em cache e não armazenados em cache.

Se um componente precisar de um dado, ele o assinará, independentemente de ser cache ou não. Por que você buscaria () dados que não tem certeza de que serão usados?

O cache deve ser implementado em um nível mais alto. Acho que esse tipo de implementação é um bom começo: http://www.syntaxsuccess.com/viewarticle/caching-with-rxjs-observables-in-angular-2.0

 getFriends(){ if(!this._friends){ this._friends = this._http.get('./components/rxjs-caching/friends.json') .map((res:Response) => res.json().friends) .publishReplay(1) .refCount(); } return this._friends; } 

Não tenho certeza se é o melhor caminho, mas é mais fácil de manter porque tem uma única responsabilidade. Os dados seriam armazenados em cache apenas se um componente os inscrever, não importa o que / quem / qual componente precisa dos dados e é o primeiro a precisar deles.

Você pode criar uma class simples Cacheable <> que ajude a gerenciar o cache de dados recuperados do servidor http ou de qualquer outra fonte:

 declare type GetDataHandler = () => Observable; export class Cacheable { protected data: T; protected subjectData: Subject; protected observableData: Observable; public getHandler: GetDataHandler; constructor() { this.subjectData = new ReplaySubject(1); this.observableData = this.subjectData.asObservable(); } public getData(): Observable { if (!this.getHandler) { throw new Error("getHandler is not defined"); } if (!this.data) { this.getHandler().map((r: T) => { this.data = r; return r; }).subscribe( result => this.subjectData.next(result), err => this.subjectData.error(err) ); } return this.observableData; } public resetCache(): void { this.data = null; } public refresh(): void { this.resetCache(); this.getData(); } } 

Uso

Declare o object <> em cache (presumivelmente como parte do serviço):

 list: Cacheable = new Cacheable(); 

e manipulador:

 this.list.getHandler = () => { // get data from server return this.http.get(url) .map((r: Response) => r.json() as string[]); } 

Chamada de um componente:

 //gets data from server List.getData().subscribe(…) 

Mais detalhes e exemplos de código estão aqui: http://devinstance.net/articles/20171021/rxjs-cacheable