How can I ensure that multiple functions in different components only make a single API call using Angular, RxJS, and caching?

huangapple go评论52阅读模式
英文:

How can I ensure that multiple functions in different components only make a single API call using Angular, RxJS, and caching?

问题

我正在使用一个缓存服务,将API数据存储在文件中,像这样:

```ts
import { Inject, Injectable } from "@angular/core";
import { Observable, firstValueFrom } from "rxjs";

@Injectable({
    providedIn: 'root'
})
export class ApiCacheService{
    api_data: any = null;

    constructor(
        private _api_service:ApiService
    ) { }
    
    public clearApiCache() {
        this.api_data=null
    }

    public async getApiData(body: any) {
        if (!this.api_data) {
            await firstValueFrom(this._api_service.getData(body)).then(res => {
                this.api_data=res
            }, err => {
                throw new Error("Error in api"+err["message"])
            })
         }
        return this.api_data
    }

}

我的第一个组件调用如下:

export class TestApiComponent {

    constructor(
        private _api_cache_service: ApiCacheService
    ) { }

    ngOnInit() {
        this.getData()
     }
    
    /**
     * function will get the data from the cache service
     */
    private async getData() {
        try {
            let body = {
                id:"1001"
            }
            let data = await this._api_cache_service.getApiData(body)
            // .... some other logic
        }catch{}
    }

}

我的第二个组件也会并行调用相同的函数,如下:

export class SetApiComponent {

    constructor(
        private _api_cache_service: ApiCacheService
    ) { }

    ngOnInit() {
        this.setFunctionData()
     }
    
    /**
     * function will get the data from the cache service
     */
    private async setFunctionData() {
        try {
            let body = {
                id:"1001"
            }
            let data = await this._api_cache_service.getApiData(body)
            // .... some other logic
        }catch{}
    }

}

现在,在调用缓存时,服务中没有数据,它将向API发送请求,然后在API响应之前,第二个服务启动了调用,此时也没有数据,然后它也会发出API调用(适用于Angular 13及以上版本)。

在这里,我需要为多个服务调用只进行一次API调用,并且一旦调用完成,需要向所有服务返回相同的数据(需要在请求体中调用另一个API以获取不同的数据体)。

英文:

i'm using a cache service where i will store the api data in the file like this

import { Inject, Injectable } from "@angular/core";
import { Observable, firstValueFrom } from "rxjs";

@Injectable({
    providedIn: 'root'
})
export class ApiCacheService{
    api_data: any = null;

    constructor(
        private _api_service:ApiService
    ) { }
    
    public clearApiCache() {
        this.api_data=null
    }

    public async getApiData(body: any) {
        if (!this.api_data) {
            await firstValueFrom(this._api_service.getData(body)).then(res => {
                this.api_data=res
            }, err => {
                throw new Error("Error in api"+err["message"])
            })
         }
        return this.api_data
    }

}

my first component call will be

export class TestApiComponent {

    constructor(
        private _api_cache_service: ApiCacheService
    ) { }

    ngOnInit() {
        this.getData()
     }
    
    /**
     * function will get the data from the cache service
     */
    private async getData() {
        try {
            let body = {
                id:"1001"
            }
            let data = await this._api_cache_service.getApiData(body)
            // .... some other logic
        }catch{}
    }

}

and my second component also will call the same function parallel to the first one like this

export class SetApiComponent {

    constructor(
        private _api_cache_service: ApiCacheService
    ) { }

    ngOnInit() {
        this.setFunctionData()
     }
    
    /**
     * function will get the data from the cache service
     */
    private async setFunctionData() {
        try {
            let body = {
                id:"1001"
            }
            let data = await this._api_cache_service.getApiData(body)
            // .... some other logic
        }catch{}
    }

}

now when calling to the cache there is no data in the service and it will send request to the api, then before api response second service initiated the call and there is no data then it will also make a api call (for angular 13 and above).

here i need to make only one api call for multiple service calls and need to return same data to all services once the call was completed (need to call another api for different body in the request body).

答案1

得分: 0

以下是您要翻译的内容:

"The most simple solution, I think, would be that you set a property in the cache service that indicates if the getApiData method is running or not. In case it is not, it fetches the data through the API and it it is, then it uses an interval to check if the response has arrived or not:



export class ApiCacheService {
  public api_data: any = null;

  private getApiDataRunning: boolean = false;

  constructor(
    private _api_service: ApiService,
  ) { }

  public clearApiCache() {
    this.api_data = null
  }

  public async getApiData(body: any) {
    if (this.api_data) {
      return this.api_data;

    } else if (this.getApiDataRunning) {
      await this.awaitApiData().then(api_data => {
        this.api_data = api_data;
      }, err => {
        throw new Error("Error in api"+err["message"]);
      });
      
      return this.api_data

    } else {
      this.getApiDataRunning = true;

      await this.fetchApiData().then(api_data => {
        this.api_data = api_data;
      }, err => {
        throw new Error("Error in api"+err["message"]);
      });

      this.getApiDataRunning = false;
      return this.api_data
    }
  }

  private async awaitApiData() {
    return await new Promise(resolve => {
      const interval = setInterval(() => {
        if (this.api_data) {
          resolve(this.api_data);
          clearInterval(interval);
        };
      }, 2000);
    });
  }

  private async fetchApiData() {
    return await firstValueFrom(this._api_service.getData(body)).then(res => {
      resolve(res);
    }, error => {
      reject(error);
    });
  }
}
英文:

The most simple solution, I think, would be that you set a property in the cache service that indicates if the getApiData method is running or not. In case it is not, it fetches the data through the API and it it is, then it uses an interval to check if the response has arrived or not:



export class ApiCacheService {
  public api_data: any = null;

  private getApiDataRunning: boolean = false;

  constructor(
    private _api_service: ApiService,
  ) { }

  public clearApiCache() {
    this.api_data = null
  }

  public async getApiData(body: any) {
    if (this.api_data) {
      return this.api_data;

    } else if (this.getApiDataRunning) {
      await this.awaitApiData().then(api_data => {
        this.api_data = api_data;
      }, err => {
        throw new Error("Error in api"+err["message"]);
      });
      
      return this.api_data

    } else {
      this.getApiDataRunning = true;

      await this.fetchApiData().then(api_data => {
        this.api_data = api_data;
      }, err => {
        throw new Error("Error in api"+err["message"]);
      });

      this.getApiDataRunning = false;
      return this.api_data
    }
  }

  private async awaitApiData() {
    return await new Promise(resolve => {
      const interval = setInterval(() => {
        if (this.api_data) {
          resolve(this.api_data);
          clearInterval(interval);
        };
      }, 2000);
    });
  }

  private async fetchApiData() {
    return await firstValueFrom(this._api_service.getData(body)).then(res => {
      resolve(res);
    }, error => {
      reject(error);
    });
  }
}

huangapple
  • 本文由 发表于 2023年5月25日 13:02:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76329077.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定