用angular2 http服务caching结果
我通过服务公开HTTP GET请求,并且有几个组件正在使用这些数据(用户的个人资料详细信息)。 我希望第一个组件请求实际执行HTTP GET请求到服务器并caching结果,以便随后的请求将使用caching的数据,而不是再次调用服务器。
下面是这个服务的一个例子,你会如何推荐用Angular2和typescript来实现这个caching层。
import {Inject, Injectable} from 'angular2/core'; import {Http, Headers} from "angular2/http"; import {JsonHeaders} from "./BaseHeaders"; import {ProfileDetails} from "../models/profileDetails"; @Injectable() export class ProfileService{ myProfileDetails: ProfileDetails = null; constructor(private http:Http) { } getUserProfile(userId:number) { return this.http.get('/users/' + userId + '/profile/', { headers: headers }) .map(response => { if(response.status==400) { return "FAILURE"; } else if(response.status == 200) { this.myProfileDetails = new ProfileDetails(response.json()); return this.myProfileDetails; } }); } }
关于你最后的评论,这是我能想到的最简单的方法:创build一个服务,将有一个属性,该属性将保存请求。
class Service { _data; get data() { return this._data; } set data(value) { this._data = value; } }
就如此容易。 在pnkrr其他的一切都将保持不变。 我从服务中删除请求,因为它会自动实例化(我们不做new Service...
,我不知道通过构造函数传递参数的简单方法)。
所以现在我们有了Service,我们现在要做的就是在我们的组件中做请求,并把它分配给Servicevariables的data
class App { constructor(http: Http, svc: Service) { // Some dynamic id let someDynamicId = 2; // Use the dynamic id in the request svc.data = http.get('http://someUrl/someId/'+someDynamicId).share(); // Subscribe to the result svc.data.subscribe((result) => { /* Do something with the result */ }); } }
请记住,我们的Service实例对于每个组件都是一样的,所以当我们为data
赋值的时候,它会反映到每个组件中。
这是一个有效的例子。
参考
- RxJS共享运营商
share()运算符只在第一个请求上工作,当所有的订阅被提供并且你创build另一个订阅时,那么它将不起作用,它将做出另一个请求。 (这种情况非常普遍,对于angular2 SPA,您总是会创build/销毁组件)
我使用ReplaySubject来存储来自http observable的值。 ReplaySubject可观察者可以为其订户服务以前的价值。
服务:
@Injectable() export class DataService { private dataObs$ = new ReplaySubject(1); constructor(private http: Http) { } getData(forceRefresh?: boolean) { // If the Subject was NOT subscribed before OR if forceRefresh is requested if (!this.dataObs$.observers.length || forceRefresh) { this.http.get('http://jsonplaceholder.typicode.com/posts/2').subscribe( data => this.dataObs$.next(data), error => { this.dataObs$.error(error); // Recreate the Observable as after Error we cannot emit data anymore this.dataObs$ = new ReplaySubject(1); } ); } return this.dataObs$; } }
组件:
@Component({ selector: 'my-app', template: `<div (click)="getData()">getData from AppComponent</div>` }) export class AppComponent { constructor(private dataService: DataService) {} getData() { this.dataService.getData().subscribe( requestData => { console.log('ChildComponent', requestData); }, // handle the error, otherwise will break the Observable error => console.log(error) ); } } }
充分工作PLUNKER
(观察控制台和networking选项卡)
我省略了userId
处理。 这将需要pipe理一组data
和一个observable
(每个请求的userId
一个)数组。
import {Injectable} from '@angular/core'; import {Http, Headers} from '@angular/http'; import {Observable} from 'rxjs/Observable'; import 'rxjs/observable/of'; import 'rxjs/add/operator/share'; import 'rxjs/add/operator/map'; import {Data} from './data'; @Injectable() export class DataService { private url:string = 'https://cors-test.appspot.com/test'; private data: Data; private observable: Observable<any>; constructor(private http:Http) {} getData() { if(this.data) { // if `data` is available just return it as `Observable` return Observable.of(this.data); } else if(this.observable) { // if `this.observable` is set then the request is in progress // return the `Observable` for the ongoing request return this.observable; } else { // example header (not necessary) let headers = new Headers(); headers.append('Content-Type', 'application/json'); // create the request, store the `Observable` for subsequent subscribers this.observable = this.http.get(this.url, { headers: headers }) .map(response => { // when the cached data is available we don't need the `Observable` reference anymore this.observable = null; if(response.status == 400) { return "FAILURE"; } else if(response.status == 200) { this.data = new Data(response.json()); return this.data; } // make it shared so more than one subscriber can get the result }) .share(); return this.observable; } } }
Plunker例子
您可以在https://stackoverflow.com/a/36296015/217408find另一个有趣的解决scheme