Datos de resultados http observables en caché angular 2
angular2-services (3)
Creo que no deberías hacer un fetch () en el constructor ni en ningún momento del ciclo de vida de angular.
Y como usted dice,
ngOnInit
no funciona en servicios angulares.
En cambio, queremos aprovechar rxjs para pasar sin problemas los valores almacenados en caché a través de la secuencia, sin que la persona que llama tenga que saber nada sobre los valores almacenados en caché y no almacenados.
Si un componente necesita datos, se suscribe a él, independientemente de si es caché o no. ¿Por qué buscaría () datos que no está seguro de que se utilizarán?
La memoria caché debe implementarse en un nivel superior. Creo que este tipo de implementación es un buen comienzo: 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;
}
No estoy seguro de que sea la mejor manera, pero es más fácil de mantener porque tiene una responsabilidad única. Los datos serían caché solo si un componente se suscribe a él, sin importar qué / quién / qué componente necesita los datos y es el primero en necesitarlos.
Esta pregunta ya tiene una respuesta aquí:
Tengo un servicio que obtiene datos a través del servicio HTTP y devuelve un objeto observable.
Después de la primera llamada, me gustaría almacenar en caché el resultado internamente en el servicio, y una vez que un nuevo componente intente obtener los datos, lo tomará del resultado almacenado en caché.
¿Hay una solución simple para esto?
Puede crear una clase simple Cacheable <> que ayuda a administrar la memoria caché de los datos recuperados del servidor http u otra fuente:
declare type GetDataHandler<T> = () => Observable<T>;
export class Cacheable<T> {
protected data: T;
protected subjectData: Subject<T>;
protected observableData: Observable<T>;
public getHandler: GetDataHandler<T>;
constructor() {
this.subjectData = new ReplaySubject(1);
this.observableData = this.subjectData.asObservable();
}
public getData(): Observable<T> {
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
Declarar objeto Cacheable <> (presumiblemente como parte del servicio):
list: Cacheable<string> = new Cacheable<string>();
y manejador:
this.list.getHandler = () => {
// get data from server
return this.http.get(url)
.map((r: Response) => r.json() as string[]);
}
Llamar desde un componente:
//gets data from server
List.getData().subscribe(…)
Más detalles y ejemplos de código están aquí: http://devinstance.net/articles/20171021/rxjs-cacheable
Si se apoya en los observables como un medio para compartir datos, puede adoptar el siguiente enfoque:
import { Injectable } from ''@angular/core'';
import { Http, Response } from ''@angular/http'';
import { Observable, ReplaySubject } from ''rxjs'';
@Injectable()
export class CachedService {
data$: Observable<Response> = this.dataSubject.asObservable();
private dataSubject = new ReplaySubject<Response>(1);
constructor(private http: Http) { }
fetch() {
this.http.get(...).subscribe(res => this.dataSubject.next(res));
}
}
Esto hará una llamada HTTP cuando se llame al método
fetch
, y cualquier suscriptor a
service.data$
obtendrá la respuesta del
ReplaySubject
.
A medida que reproduce los valores anteriores, los suscriptores que se unan
después de que se
resuelva la llamada HTTP seguirán recibiendo la respuesta anterior.
Si desea activar una actualización, puede llamar a
service.fetch()
para iniciar una nueva llamada HTTP y todos los suscriptores se actualizarán una vez que llegue la nueva respuesta.
Sus componentes se verían así:
@Component({ ... })
export class SomeComponent implements OnInit {
constructor(private service: CachedService) { }
ngOnInit() {
this.service.fetch();
this.service.data$.subscribe(...);
}
}
Recientemente escribí un artículo de blog sobre este enfoque para mis colegas: http://blog.jonrshar.pe/2017/Apr/09/async-angular-data.html