当前位置: 首页 > 知识库问答 >
问题:

使用 Angular2 HTTP 服务缓存结果 [重复]

曾飞沉
2023-03-14

我通过一个服务公开了一个HTTP GET请求,几个组件正在使用这个数据(一个用户的配置文件细节)。我希望第一个组件请求实际执行对服务器的HTTP GET请求并缓存结果,这样后续的请求将使用缓存的数据,而不是再次调用服务器。

这里有一个服务的例子,你会建议如何用Angular2和typescript实现这个缓存层。

import {Inject, Injectable} from 'angular2/core';
import {Http, Headers} from "angular2/http";
import {JsonHeaders} from "./BaseHeaders";
import {ProfileDetails} from "../models/profileDetails";

@Injectable()
export class ProfileService{
    myProfileDetails: ProfileDetails = null;

    constructor(private http:Http) {

    }

    getUserProfile(userId:number) {
        return this.http.get('/users/' + userId + '/profile/', {
                headers: headers
            })
            .map(response =>  {
                if(response.status==400) {
                    return "FAILURE";
                } else if(response.status == 200) {
                    this.myProfileDetails = new ProfileDetails(response.json());
                    return this.myProfileDetails;
                }
            });
    }
}

共有3个答案

慕祯
2023-03-14

关于您的最后一条评论,这是我能想到的最简单的方法:创建一个将具有一个属性的服务,该属性将保存请求。

class Service {
  _data;
  get data() {
    return this._data;
  }
  set data(value) {
    this._data = value;
  }
}

就这么简单。plnkr中的其他所有东西都不会受到影响。我从服务中删除了请求,因为它将被自动实例化(我们不做< code >新服务...,并且我不知道通过构造函数传递参数的简单方法)。

现在,我们有了服务,我们现在要做的是在组件中发出请求,并将其分配给服务变量data

class App {
  constructor(http: Http, svc: Service) {

    // Some dynamic id
    let someDynamicId = 2;

    // Use the dynamic id in the request
    svc.data = http.get('http://someUrl/someId/'+someDynamicId).share();

    // Subscribe to the result
    svc.data.subscribe((result) => {
      /* Do something with the result */
    });
  }
}

请记住,我们的服务实例对于每个组件都是相同的,因此当我们将值分配给data时,它将反映在每个组件中。

这是plnkr的一个工作示例。

参考

  • RxJS 共享运算符
哈涵容
2023-03-14

我省略了userId处理。相反,它需要管理data数组和可观察数组(每个请求的userId一个)。

import {Injectable} from '@angular/core';
import {Http, Headers} from '@angular/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/observable/of';
import 'rxjs/add/operator/share';
import 'rxjs/add/operator/map';
import {Data} from './data';

@Injectable()
export class DataService {
  private url:string = 'https://cors-test.appspot.com/test';

  private data: Data;
  private observable: Observable<any>;

  constructor(private http:Http) {}

  getData() {
    if(this.data) {
      // if `data` is available just return it as `Observable`
      return Observable.of(this.data); 
    } else if(this.observable) {
      // if `this.observable` is set then the request is in progress
      // return the `Observable` for the ongoing request
      return this.observable;
    } else {
      // example header (not necessary)
      let headers = new Headers();
      headers.append('Content-Type', 'application/json');
      // create the request, store the `Observable` for subsequent subscribers
      this.observable = this.http.get(this.url, {
        headers: headers
      })
      .map(response =>  {
        // when the cached data is available we don't need the `Observable` reference anymore
        this.observable = null;

        if(response.status == 400) {
          return "FAILURE";
        } else if(response.status == 200) {
          this.data = new Data(response.json());
          return this.data;
        }
        // make it shared so more than one subscriber can get the result
      })
      .share();
      return this.observable;
    }
  }
}

Plunker示例

你可以在https://stackoverflow.com/a/36296015/217408找到另一个有趣的解决方案

岳景明
2023-03-14

共享()运算符只在第一个请求时工作,当所有订阅都已服务并创建另一个订阅时,它将不工作,它将发出另一个请求。(这种情况很常见,对于angular2 SPA,您总是创建/销毁组件)

我使用ReplaySubject来存储http observable中的值。可观察的ReplaySubject可以为其订户提供以前的值服务:

@Injectable()
export class DataService {
    private dataObs$ = new ReplaySubject(1);

    constructor(private http: HttpClient) { }

    getData(forceRefresh?: boolean) {
        // If the Subject was NOT subscribed before OR if forceRefresh is requested 
        if (!this.dataObs$.observers.length || forceRefresh) {
            this.http.get('http://jsonplaceholder.typicode.com/posts/2').subscribe(
                data => this.dataObs$.next(data),
                error => {
                    this.dataObs$.error(error);
                    // Recreate the Observable as after Error we cannot emit data anymore
                    this.dataObs$ = new ReplaySubject(1);
                }
            );
        }

        return this.dataObs$;
    }
}

组件:

@Component({
  selector: 'my-app',
  template: `<div (click)="getData()">getData from AppComponent</div>`
})
export class AppComponent {
    constructor(private dataService: DataService) {}

getData() {
    this.dataService.getData().subscribe(
        requestData => {
            console.log('ChildComponent', requestData);
        },
        // handle the error, otherwise will break the Observable
        error => console.log(error)
    );
}
    }
}

完全工作的PLUNKER
(观察控制台和网络选项卡)

 类似资料:
  • 结果缓存 1,用于加速热门数据的访问速度,Dubbo 提供声明式缓存,以减少用户加缓存的工作量 2。 缓存类型 lru 基于最近最少使用原则删除多余缓存,保持最热的数据被缓存。 threadlocal 当前线程缓存,比如一个页面渲染,用到很多 portal,每个 portal 都要去查用户信息,通过线程缓存,可以减少这种多余访问。 jcache 与 JSR107 集成,可以桥接各种缓存实现。 缓存

  • 我正在使用Jmeter对我的ASP.NET应用程序进行负载测试。 我正在测试搜索功能,什么是在获得结果的响应时间。 我面临的问题是,当我第一次搜索时,说我搜索了“我很好”,并说它花了9876毫秒,下次我搜索同样的东西只需要4567毫秒,第三次只需要4234毫秒。 我正在使用HTTP缓存管理器,我已经检查了“每次迭代都清除缓存”。我还使用了Http Cookie管理器,并检查了“每次迭代清除Cook

  • Quarkus有类似于开箱即用?(在文件中找不到任何提及) 要穿上某种服务方式, 这将在一段时间内保留/缓存prev响应,并保留调用堆栈/日志。 类似于那个Spring注释?

  • 问题内容: 我对来自JQuery Ajax请求的Internet Explorer缓存结果存在严重问题。 我的网页上有标题,每次用户导航到新页面时标题都会更新。页面加载后,我就执行此操作 它只是将标头信息注入页面。您可以通过访问www.wikipediamaze.com进行检查,然后登录并开始创建新拼图。 在我测试过的每种浏览器(谷歌浏览器,Firefox,Safari,Internet Expl

  • 问题内容: 我在Internet Explorer中的页面出现问题。我有一个Ajax调用,在其他浏览器中,当我单击该链接时,该调用会传递到控制器中并正确加载数据。但是在IE中,一次加载后,它消失了,而我却没有通过控制器就获得了相同的旧结果。 问题答案: 尝试: 放置在控制器类中的此属性禁用缓存。由于不需要在应用程序中缓存,因此将其放置在BaseController类中: 这是有关OutputCac

  • 我正在实现一个使用Swift Stack的Joss客户机调用外部服务的Lagom服务。如何缓存此信息以避免每次调用服务时都调用外部服务?