如何在 Angular 服务中存储从 api 接收的数据并避免多次 api 调用?

Utt*_*ndi 6 rxjs angular

我正在使用 Angular (v6) 服务从后端获取数据并将其存储在变量中。我只想调用 api 一次,并在不同组件需要时提供数据。

问题是我从不同的组件调用服务中的 getPlans() 函数来获取数据,并且对于每个调用,我在浏览器的网络选项卡中看到一个 api 调用。

如何避免每次调用 getPlans() 函数时都调用并提供调用 api 一次的数据并将其存储到变量中?

export class PlansService {
  private plansData:any = {};

  constructor(private httpCallService: HttpCallService, private http: HttpClient) { 

    this.plansData = this.httpCallService.getHttpResponse("GET_PLANS");

  }
  getPlans(): Observable<any>{
    return this.plansData;
   }

}
Run Code Online (Sandbox Code Playgroud)

wen*_*jun 5

这可以通过 RxJs 的shareReplay()来完成。根据变更日志

shareReplay 返回一个可观察量,它是通过 ReplaySubject 多播的源。该重放主题会在源发生错误时回收,但不会在源完成时回收。这使得 shareReplay 非常适合处理缓存 AJAX 结果之类的事情,因为它是可重试的。然而,它的重复行为与共享不同,因为它不会重复源可观察值,而是重复源可观察值的值。

这使得 user 非常shareReplay()适合您的用例。

请记住在您的服务上也导入 shareReplay() 。

import { shareReplay } from 'rxjs/operators';
.
.

export class PlansService {
  private plansData: Observable<any>;

  constructor(private httpCallService: HttpCallService, private http: HttpClient) { 

    this.plansData = this.httpCallService.getHttpResponse("GET_PLANS")
      .pipe(
        shareReplay()
      );

  }

  getPlans(): Observable<any>{
    return this.plansData;
   }

}
Run Code Online (Sandbox Code Playgroud)

然后,您可以在需要它的组件上返回可观察量,并且如果您查看 Inspect Element 工具上的网络请求选项卡,则不会触发其他 HTTP 请求,因为每次调用时都会返回带有缓存值的可观察量getPlans()


Fat*_*med 4

您可以使用ReplaySubjectBehaviorSubject来实现该功能,如果您使用ReplaySubject,您必须指定要存储多少旧值,以便订阅者稍后可以访问,BehaviorSubject只能保留最后一个值

 import { ReplaySubject } from 'rxjs';

 ....
 @Injectable()
 export class SharedService {
 plans$: Observable<Plan[]> = this.plansSubject.asObservable(); 
 private plansSubject = new ReplaySubject<Plan[]>(1);

 constructor(private http: HttpClient) { }
 getPlans(){
   this.http.get().subscribe(res => this.plansSubject.next(res.plans)); // get array of plans
 }
}
Run Code Online (Sandbox Code Playgroud)

您可以像这样在组件中获取数据:

constructor(private sharedService: SharedService) { }

ngOnInit() {
 this.sharedService.getPlans(); // to get called only the first time to get data
 this.service.plans$.subscribe(...); // you have your data here without anu additional http call 
}
Run Code Online (Sandbox Code Playgroud)

如果你想刷新数据,你可以调用该方法

this.sharedService.getPlans();
Run Code Online (Sandbox Code Playgroud)

对于BehaviorSubject来说,这是完全相同的事情,这里会发生什么变化

plans$: Observable<Plan[]> = this.plansSubject.asObservable(); 
private plansSubject = new BehaviorSubject<Plan[]>;
Run Code Online (Sandbox Code Playgroud)

您可以在组件内部订阅以获取数据,也可以使用BehaviorSubject.value访问它

constructor(private sharedService: SharedService) { }

ngOnInit() {
 this.service.plans$.subscribe((plans) => console.log(plans));
 // or access the value directly
 console.log(this.service.plans$.value)    
}
Run Code Online (Sandbox Code Playgroud)