簡體   English   中英

在Angular 4中從HttpClient緩存數據

[英]Caching Data From HttpClient in Angular 4

我有一個問題,使我的緩存更簡單。 我認為有更好的方法來做到這一點。 我的問題是我必須在每個get()函數中執行此“緩存”代碼,這會導致代碼更長。 有誰幫助如何做到這一點最好的方式? 謝謝。 這是我的代碼如下。 我在我的代碼中做的是我在news.service.ts中執行get()函數以從http獲取數據,並在我的新聞列表中訂閱它。

news.service.ts

getAllNews() {

    if(this.newslist != null) {
      return Observable.of(this.newslist);
    } 

    else {

      return this.httpClient
        .get('http://sample.com/news')
        .map((response => response))
        .do(newslist => this.newslist = newslist)
        .catch(e => {
            if (e.status === 401) {
                return Observable.throw('Unauthorized');           
            }

        });
    }
  }

新聞list.service.ts

 this.subscription = this.newsService.getAllNews()
      .subscribe(
        (data:any) => {
          console.log(data);
          this.newslists = data.data.data;
        },
        error => {
          this.authService.logout()
          this.router.navigate(['signin']);
        });
  }

如果您打算使用通用的,可以用於不同的API調用或服務,那么您可以執行以下操作:

import { Injectable } from '@angular/core';
import { HttpClient } from "@angular/common/http";
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';

class CacheItem<T> {
  url: string;
  timestampCached: number;
  data: T;
}

@Injectable({
  providedIn: 'root'
})
export class MyCachedHttpClient {
  cache: CacheItem<any>[] = [];

  constructor(
    private http: HttpClient,
  ) { }

  get<T>(url: string, cacheTime?: number, forceRefresh: boolean = false)
  : Observable<T> {
    let cachedItem: CacheItem<T> = this.getCachedItem<T>(url);

    if (cachedItem != undefined && !forceRefresh) {
      let expireDate = cachedItem.timestampCached + cacheTime;
      if (Date.now() < expireDate) {
        return of(cachedItem.data);
      }
    }

    return this.http.get<T>(url).pipe(
      map(data => {
        if (cacheTime) { // if we actually want to cache the result
          if (cachedItem == undefined) {
            cachedItem = new CacheItem();
            cachedItem.url = url;
            this.cache.push(cachedItem);
          }
          cachedItem.data = data;
          cachedItem.timestampCached = Date.now();
        }
        return data;
      })
    );
  }

  private getCachedItem<T>(url: string): CacheItem<T> {
    return this.cache.find(item => item.url == url);
  }
}

然后在任何地方使用MyCachedHttpClient而不是HttpClient

筆記:

  • 這適用於Angular 6 / RxJS 6.如果您在下面,請參閱編輯歷史記錄中的代碼。
  • 這只是一個基本的實現,隱藏了HttpClientget()函數的許多功能,因為我沒有在這里重新實現options參數。

我不太清楚news.service.tsnews-list.service.ts之間的區別是什么,但主要的概念是你需要分開關注點。 您可以做的最基本的分離是從“數據消費者”中分離“數據提供者”

數據提供商

這可以是獲取和管理數據的任何內容。 無論是內存緩存數據,服務調用等。在您的示例中,在我看來, news.service.ts它是與新聞相關的所有內容的Web API客戶端/代理。

如果這是一個小文件,您可以將所有與新聞相關的緩存管理移動到此文件或...創建另一個管理緩存並包裝news.service.ts 該組件將從其緩存中提供數據,如果緩存不存在或已過期,則它將調用news.service.ts方法。 這樣news.service.ts唯一的責任就是向API發出ajax請求。

這是一個沒有承諾,可觀察或錯誤處理的例子,只是為了給你一個想法......

class NewsProvider{

    constructor(){
        this.newsCache = [];
    }

    getNewsItemById(id){
        const item = this.newsCache.filter((i) => {i.id === id});

        if(item.length === 1) return item[0];

        this.newsCache = newsService.getAllNews();

        item = this.newsCache.filter((i) => {i.id === id});

        if(item.length === 1) return item[0];
        else return null;
    }
}

數據消費者

這些將是需要數據的任何組件,主頁中的新聞自動收錄器,導航菜單中某處的徽章通知......可能存在需要與新聞相關的數據的任何組件(或視圖)。 因此,這些組件/視圖不需要知道數據來自何處。

這些組件將使用“數據提供者”作為主要數據源

摘要

只需要(可以)在一個地方管理緩存以及與網絡相關的操作

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM