在整个Angular应用程序中共享API调用的结果

时间:2018-12-05 07:45:20

标签: angular

如何存储或缓存局部变量,以便可以在整个应用程序中共享API调用的结果?

我有以下Angular 6模块,该模块基本上创建了一个提到指令,以便能够执行许多应用程序中流行的@提及:

@NgModule({
    imports: [
        CommonModule
    ],
    exports: [
        MentionDirective,
        MentionListComponent
    ],
    entryComponents: [
        MentionListComponent
    ],
    declarations: [
        MentionDirective,
        MentionListComponent
    ]
})
export class MentionModule {
    static forRoot(): ModuleWithProviders {
        return {
            ngModule: MentionModule
        };
    }
}

这是实际的指令:

export class MentionDirective implements OnInit, OnChanges {
items: any[];

constructor(
  public autocompletePhrasesService: AutocompletePhrasesService
) { }

  ngOnInit() {
    this.autocompletePhrasesService.getAll()
      .pipe(first())
      .subscribe(
        result => {
          this.items = result;
        },
        () => { });

该指令在我的核心模块中调用一个函数来检索数据:

export class AutocompletePhrasesService {

    public autoCompletePhrases: string[];

    constructor(private http: HttpClient) { }

    getAll(): Observable<string[]> {
        return this.http.get<string[]>(this.baseUrl + '/getall');
    }

我的问题是,此指令在单个页面上可能有20-30个实例,并且该指令的每个实例都会调用API。如何更改代码,以便每个应用程序实例仅调用一次API?

数据通常不会从API更改。

我尝试将服务的结果存储在公共autoCompletePhrases变量中,并且仅在它为空但没有用时才调用它

2 个答案:

答案 0 :(得分:1)

您想要一些类似“缓存”的内容。它易于维护,让人喜欢

data:any;
getData()
{
    if (!this.data)
      return this.httpClient.get(....).pipe(
        tap(result=>{
            this.data=result
        }))
    return of(this.data)
}

当您订阅“ getData”时,可能会发生两件事:this.data具有值,然后返回具有可观察性的数据。或此数据没有值,然后返回get并将结果存储在data中-tap在subscription-之后执行。因此,您始终订阅“ getData”,但是该服务仅在没有数据的情况下才调用API(注意:一次可能会发生一次调用,而对API会多次调用)

答案 1 :(得分:1)

以下是一些AngularJS / TypeScript代码,以演示如何处理此问题的逻辑。抱歉,但我没有时间将其转换为Angular。我确实相信那里也有可以更完整地处理缓存的软件包,但这是手动的方式:)

private printerList: SelectItem[] = [];
private printerPromises: IDeferred<SelectItem[]>[] = [];
private printersLoading: boolean = false;
private printersLoaded: boolean = false;

public getPDFPrinterList(): ng.IPromise<SelectItem[]> {
  let defer: IDeferred<SelectItem[]> = this.$q.defer<SelectItem[]>();

  this.printerPromises.push(defer);

  if (this.printersLoading) {
      return defer.promise;
  }

  if (this.printersLoaded) {
      for (let i = 0; i < this.printerPromises.length; i++) {
          this.printerPromises[i].resolve(this.printerList);
      }
      this.printerPromises = [];
  } else {
      this.printersLoading = true;
      this.$http.get<SelectItem[]>(this.printerListUrl, { cache: false }).then((response: ng.IHttpResponse<SelectItem[]>) => {
          if (response.data) {
              this.printerList = response.data;
              for (let i = 0; i < this.printerPromises.length; i++) {
                  this.printerPromises[i].resolve(this.printerList);
              }
              this.printerPromises = [];
              this.printersLoaded = true;
          } else {
              console.log('Server Error Obtaining Printer List');
              for (let i = 0; i < this.printerPromises.length; i++) {
                  this.printerPromises[i].reject('Server Error');
              }
              this.printerPromises = [];
          }
          this.printersLoading = false;
      }, (response: ng.IHttpResponse<any>) => {
          if (response.data) {
             console.log(response.data.Message ? response.data.Message : response.data);
          }
          for (let i = 0; i < this.printerPromises.length; i++) {
              this.printerPromises[i].reject('Server Error');
          }
          this.printerPromises = [];
      });
  }

  return defer.promise;
}