【问题标题】:Angular: multiple reciepients of data from endpointAngular:来自端点的多个数据接收者
【发布时间】:2021-10-12 09:20:00
【问题描述】:

前提条件
我有以下情况:

  1. 在后端我有一个端点,它提供数据。数据很少更改。
  2. 在前端我有几个组件,在加载后需要来自 p.1 的数据。

问题
如何避免对后端的多个请求(= 如何将第一个请求的结果共享给服务方法的所有其他调用)。

源代码-服务

@Injectable()
export class ConfigurationService {

  private ConfigurationUrl: string = 'api/configurations/';
  private httpHeaders: HttpHeaders;
  // ...
  constructor(private httpClient: HttpClient) { 
  }
  // ...
  loadCommonSettings(): Observable<CommonSettings> {
    return this.httpClient.get<CommonSettings>(this.ConfigurationUrl + "common");
  }
  // ...
}

源代码 - 组件

export class HomeComponent {
  constructor(public dialog: MatDialog,  private configurationService: ConfigurationService, private _snackBar: MatSnackBar) { 
  }

  isNewDisabled: boolean = true;
  commonSettings: CommonSettings;

  ngOnInit() {
    this.loadCommonSettings();
  }
  //...

  loadCommonSettings() {
    this.configurationService.loadCommonSettings().subscribe(
      res => {
        this.isNewDisabled = false;
        this.commonSettings = res;
      },
      err => {
        this.openErrorDialog("Error", "Error on data loading");
      }
    );
  }
  //...
}

问题 每次调用 loadCommonSettings 服务函数都会向服务发起一个新请求。

假设

  1. 我想将数据存储在服务中,就像存储在缓存中一样,但无论如何我几乎同时调用了 2 个服务方法。
  2. 在这种情况下,Subjects 可能会有所帮助,但我完全不确定(因为看起来,Observables 也完全可以用于此类调用)。

【问题讨论】:

标签: angular rxjs request observable angular2-observables


【解决方案1】:

正如您已经想到的那样,缓存在这里是一个明智的选择。 在下面的示例中为您提供服务。您也可以使用 BehaviorSubject 代替 ReplaySubject 并使用 undefined 对其进行初始化。

@Injectable()
export class ConfigurationService {

  private ConfigurationUrl: string = 'api/configurations/';
  private httpHeaders: HttpHeaders;
  private commonSettings$: Subject<string>;
  
  // ...
  constructor(private httpClient: HttpClient) { 
  }
  // ...
  loadCommonSettings(): Observable<string> {
    if (!this.commonSettings$) {
      this.commonSettings$ = new ReplaySubject<string>(1);
      this.httpClient.get<string>(this.ConfigurationUrl + "common")
        .subscribe(data => this.commonSettings$.next(data));
    }
    return this.commonSettings$;
  }
  // ...

这里只有对服务的第一次调用是开始一个 http 调用。包括第一个电话在内的所有电话都只返回主题。

【讨论】:

  • 非常感谢。它运作良好。我想,现在我需要了解更多关于 ReplaySubject 的信息。再次非常感谢:-)
【解决方案2】:

以下是不使用Subjects的解决方案

选项 1:使用ShareReplay

loadCommonSettings(): Observable<CommonSettings> {
    return this.httpClient.get<CommonSettings>(this.ConfigurationUrl + "common").pipe(
        take(1),
        shareReplay(1)
    );
 }

选项 2: 使用本地变量来保存结果

// declare variable to hold cache
private cachedSetting: CommonSettings = null;

loadCommonSettings(): Observable<CommonSettings> {
    // if cachedSetting already available then return same
    if(cachedSetting){
        return of(this.cachedSetting);
    }
    
    return this.httpClient.get<CommonSettings>(this.ConfigurationUrl + "common").pipe(
        tap(response => this.cachedSetting = response)
    );
 }

使用的进口:

import { shareReplay, take, tap } from 'rxjs/operators';
import { of } from 'rxjs';

【讨论】:

  • 非常感谢您的回答。我已经尝试了这两种选择,似乎缺少一些东西。我仍然看到重复的请求。我将了解更多有关 ReplaySubject 的信息,并尝试修复这两种解决方案。它似乎与 BozziDev 的评论非常相似。再次感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-03
  • 1970-01-01
  • 2022-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多