使用Angular2 HTTP服务缓存机制

时间:2016-11-11 21:48:03

标签: http caching angular service observable

我通过服务公开HTTP GET请求,并且有几个组件正在使用此数据(国家/地区列表)。我希望第一个组件请求实际执行到服务器的HTTP GET请求并缓存结果,以便后续请求将使用缓存数据,而不是再次调用服务器。

这是我的服务:

import {Injectable} from '@angular/core'
import {Subject} from 'rxjs/Subject';
import {Message, SelectItem} from 'primeng/primeng';
import {Http, Headers, RequestOptions} from '@angular/http';
import {environment} from '../../../environments/environment';
import {Country} from '../../domain/country';
import {Response} from "@angular/http";
import {Observable} from 'rxjs/Observable';
import {ReplaySubject} from "rxjs/Rx";
import "rxjs/add/observable/of";

@Injectable()
export class ListsService {

  private _listOfCountries:SelectItem[]=[];
  private countries:SelectItem[]=[];

  private options = new RequestOptions({headers: new Headers({'Content-Type': 'application/json'})});

  constructor(private http:Http) {
    console.log("create ListsService");
  }

  /**
   * Get all countries
   */
  getListOfCountries():Observable<SelectItem[]> {
    console.log('this._listOfCountries==');
    console.log(this._listOfCountries);
    let countries$ = this._listOfCountries.length > 0? Observable.of(this._listOfCountries): this.http
      .get(`${environment.backend_url}api/countries`, this.options)
      .map(this.mapCountries)
      .catch(this.handleError);
    return countries$;
  }

  private mapCountries(response:Response):SelectItem[] {
    let countries:Country[] = response.json();
    let selectItems:SelectItem[] = countries.map((c) => {
      return {label: c.frLabel, value: c.id}
    });
    this._listOfCountries = selectItems.map(a => Object.assign({}, a));
    console.log('this._listOfCountries==');
    console.log(this._listOfCountries);
    return selectItems;
  }

  private handleError(error:any) {
    let errorMsg = error.message || `Error during retrieving data from the API`;
    return Observable.throw(errorMsg);
  }
}

我正在将我的服务注入以下组件:

constructor(
              private listService:ListsService,
              private router: Router,
              public fb:FormBuilder) {
...
}

  ngOnInit() {

    this.listService.getListOfCountries().subscribe(countries => {
      console.log(countries);
      this.listOfCountries = countries;
    });
}

我只在我的root模块app.module.ts上声明服务,如下所示:

...
import {ListsService} from "./shared/services/lists.service";

@NgModule({
  declarations: [
    AppComponent,
    IntroComponent,
  ],
  imports: [
    // @angular
    BrowserModule,
    FormsModule,
    ReactiveFormsModule,
    HttpModule,
    RouterModule.forRoot(routes, {useHash: true}),
    ...
    //app
    AdministrationModule,
  ],
  providers: [MessageService, ListsService],
  bootstrap: [AppComponent]
})
export class AppModule { }

我期望服务在字段_listOfCountries中维护数据,但它总是初始化为空数组,所以我没有达到预期的行为。

任何人都可以指出我如何解决这个问题并建议解决此问题的最佳方法?

溶液*: 我修改了服务,如下所示:

@Injectable()
export class ListsService {

  private countriesSubject: Subject<SelectItem[]>;
  private countriesRequest: Observable<SelectItem[]>;

  private options = new RequestOptions({headers: new Headers({'Content-Type': 'application/json'})});

  constructor(private http:Http) {
    console.log("create ListsService");
    this.countriesSubject = new ReplaySubject<SelectItem[]>(1);
  }

  /**
   * Get all countries
   */
  getListOfCountries(refresh: boolean = false) {
    if (refresh || !this.countriesRequest) {
      this.countriesRequest =  this.http
        .get(`${environment.backend_url}api/countries`, this.options)
        .map(this.mapCountries)
        .catch(this.handleError);

      this.countriesRequest.subscribe(
        result => this.countriesSubject.next(result),
        err => this.countriesSubject.error(err)
      );
    }
    return this.countriesSubject.asObservable();
  }

  private mapCountries(response:Response):SelectItem[] {
    console.log('mapCountries');
    let countries:Country[] = response.json();
    let selectItems:SelectItem[] = countries.map((c) => {
      return {label: c.frLabel, value: c.id}
    });
    return selectItems;
  }
}

在我的组件上:

ngOnInit() {

    this.listService.getListOfCountries().take(1).subscribe(countries => {
      this.listOfCountries = countries;
    });

  }

1 个答案:

答案 0 :(得分:0)

使用ListsService的组件可以订阅Observable,然后维护自己的缓存。

@Component({...})
export class SomeComponent implements OnInit {
  private countries:SelectItem[]=[];

  constructor(private listsService: ListsService) {}

  ngOnInit() {
    this.listsService.getListOfCountries()
      .subscribe((countries: SelectItem[]) => {
        this.countries = countries;
      }
  }
}