webentwicklung-frage-antwort-db.com.de

Daten von HttpClient im Cache zwischenspeichern Angular 4

ich habe ein Problem damit, das Caching einfacher zu gestalten. Ich denke, dass es einen besseren Weg gibt, dies zu tun. Mein Problem ist, dass ich diese "Zwischenspeicherung" von Codes in jeder get () - Funktion ausführen muss, was zu längeren Codes führt. Hilft jemand, wie man das am besten macht? Vielen Dank. Hier sind meine Codes unten. Was ich in meinen Codes getan habe, ist, dass ich die get () - Funktion in meinem news.service.ts mache, um Daten vom http zu erhalten, und ich abonniere sie in meiner Newsliste.

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

Wenn Sie etwas generisches haben wollten, das Sie für verschiedene API-Aufrufe oder -Dienste verwenden können, können Sie Folgendes tun:

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

Und dann einfach MyCachedHttpClient anstelle von HttpClient überall verwenden.

Anmerkungen:

  • Dies ist für Angular 6/RxJS 6. Siehe Code aus "Verlauf bearbeiten", wenn Sie sich unten befinden.
  • Dies ist nur eine grundlegende Implementierung, die viele Funktionen der get()-Funktion von HttpClient verbirgt, da ich den Parameter options hier nicht neu implementiert habe.
2
MA-Maddin

Ich bin mir nicht sicher, was der Unterschied zwischen news.service.ts und news-list.service.ts ist, aber das Hauptkonzept besteht darin, dass Sie Bedenken voneinander trennen müssen. Die grundlegendste Trennung, die Sie tun können, ist die Trennung von "Datenanbietern" und "Datenkonsumenten".

Datenanbieter

Dies kann alles sein, was Daten abruft und verwaltet. Ob zwischengespeicherte Daten im Arbeitsspeicher, ein Serviceabruf usw. In Ihrem Beispiel scheint mir, dass news.service.ts ein Web-API-Client/Proxy für alles ist, was mit Nachrichten zu tun hat. 

Wenn dies eine kleine Datei ist, können Sie die gesamte Cache-Verwaltung für Nachrichten in diese Datei verschieben oder ... eine andere Komponente erstellen, die den Cache verwaltet und news.service.ts umschließt. Diese Komponente würde Daten aus ihrem Cache bereitstellen. Wenn der Cache nicht vorhanden ist oder abgelaufen ist, werden news.service.ts-Methoden aufgerufen. Auf diese Weise besteht die einzige Verantwortung von news.service.ts darin, Ajax-Anforderungen an die API zu stellen.

Hier ein Beispiel ohne Versprechen, Observables oder Fehlerbehandlung, nur um Ihnen eine Vorstellung zu geben ...

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

Datenverbraucher

Dies wäre eine beliebige Komponente, die Daten benötigt, ein Nachrichtenticker auf der Startseite, eine Benachrichtigung über eine Badge irgendwo im Navigationsmenü. Möglicherweise gibt es Komponenten (oder Ansichten), die newsbezogene Daten benötigen. Aus diesem Grund sollten diese Komponenten/Ansichten nicht wissen müssen, woher die Daten stammen.

Diese Komponenten verwenden "Datenanbieter" als Hauptdatenquelle

Zusammenfassung

Der Cache muss nur an einem einzigen Ort verwaltet werden (und kann auch verwaltet werden) sowie netzwerkbezogene Vorgänge

1
Leo