What is the correct way to share the result of an Angular Http network call in RxJs 5?

前端 未结 21 1285
广开言路
广开言路 2020-11-21 06:11

By using Http, we call a method that does a network call and returns an http observable:

getCustomer() {
    return          


        
21条回答
  •  走了就别回头了
    2020-11-21 06:14

    I wrote a cache class,

    /**
     * Caches results returned from given fetcher callback for given key,
     * up to maxItems results, deletes the oldest results when full (FIFO).
     */
    export class StaticCache
    {
        static cachedData: Map = new Map();
        static maxItems: number = 400;
    
        static get(key: string){
            return this.cachedData.get(key);
        }
    
        static getOrFetch(key: string, fetcher: (string) => any): any {
            let value = this.cachedData.get(key);
    
            if (value != null){
                console.log("Cache HIT! (fetcher)");
                return value;
            }
    
            console.log("Cache MISS... (fetcher)");
            value = fetcher(key);
            this.add(key, value);
            return value;
        }
    
        static add(key, value){
            this.cachedData.set(key, value);
            this.deleteOverflowing();
        }
    
        static deleteOverflowing(): void {
            if (this.cachedData.size > this.maxItems) {
                this.deleteOldest(this.cachedData.size - this.maxItems);
            }
        }
    
        /// A Map object iterates its elements in insertion order — a for...of loop returns an array of [key, value] for each iteration.
        /// However that seems not to work. Trying with forEach.
        static deleteOldest(howMany: number): void {
            //console.debug("Deleting oldest " + howMany + " of " + this.cachedData.size);
            let iterKeys = this.cachedData.keys();
            let item: IteratorResult;
            while (howMany-- > 0 && (item = iterKeys.next(), !item.done)){
                //console.debug("    Deleting: " + item.value);
                this.cachedData.delete(item.value); // Deleting while iterating should be ok in JS.
            }
        }
    
        static clear(): void {
            this.cachedData = new Map();
        }
    
    }
    

    It's all static because of how we use it, but feel free to make it a normal class and a service. I'm not sure if angular keeps a single instance for the whole time though (new to Angular2).

    And this is how I use it:

                let httpService: Http = this.http;
                function fetcher(url: string): Observable {
                    console.log("    Fetching URL: " + url);
                    return httpService.get(url).map((response: Response) => {
                        if (!response) return null;
                        if (typeof response.json() !== "array")
                            throw new Error("Graph REST should return an array of vertices.");
                        let items: any[] = graphService.fromJSONarray(response.json(), httpService);
                        return array ? items : items[0];
                    });
                }
    
                // If data is a link, return a result of a service call.
                if (this.data[verticesLabel][name]["link"] || this.data[verticesLabel][name]["_type"] == "link")
                {
                    // Make an HTTP call.
                    let url = this.data[verticesLabel][name]["link"];
                    let cachedObservable: Observable = StaticCache.getOrFetch(url, fetcher);
                    if (!cachedObservable)
                        throw new Error("Failed loading link: " + url);
                    return cachedObservable;
                }
    

    I assume there could be a more clever way, which would use some Observable tricks but this was just fine for my purposes.

提交回复
热议问题