web-dev-qa-db-ja.com

Angular 4でのHttpClientからのデータのキャッシュ

キャッシュをより簡単にするのに問題があります。これを行うにはもっと良い方法があると思います。私の問題は、すべての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');           
            }

        });
    }
  }

news-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']);
        });
  }
7
Joseph

さまざまな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の場合です。以下の場合は、編集履歴のコードを参照してください。
  • ここではHttpClientパラメータを再実装しなかったため、これはoptionsget()関数の多くの機能を隠す基本的な実装にすぎません。
2

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;
    }
}

データ利用者

これらは、データを必要とするコンポーネント、ホームページのニュースティッカー、ナビゲーションメニューのどこかにあるバッジ通知などです。ニュース関連のデータを必要とするコンポーネント(またはビュー)が存在する可能性があります。そのため、これらのコンポーネント/ビューは、データがどこから来ているのかについて何も知る必要はありません。

これらのコンポーネントは、データの主要なソースとして「データプロバイダー」を使用します

概要

キャッシュは、ネットワーク関連の操作だけでなく、1つの場所で管理するだけでよい(管理できる)

1
Leo