typescript 在驯服重复Angular组件的http调用时,寻求利用任何RxJs方法的帮助

szqfcxe2  于 2023-05-19  发布在  TypeScript
关注(0)|答案(2)|浏览(82)

我有一个Angular父组件,它控制一个对象列表,即spacecrafts。对象数组被加载到父组件中,我将其称为list,我的子组件,或cards,每个组件都接收该对象的一个示例以显示其信息。我使用*NgFor,调用组件选择器,并通过@Input传入spacecraft
注意:有两个不同的组件使用这种逻辑,一个是以“列表视图”显示我们的航天器,另一个是允许我们显示“网格视图”-类似于桌面文件夹。有一个UI开关来确定执行哪个*ngFor循环- list或grid。它们使用父组件list中的相同spacecraft列表,并根据需要在每个子组件中获取少量附加信息。
当我的spacecraft列表被返回时,它们包含对象/数组,其中一个数组是航天器的Tasks[]。这些Spacecraft被小心地加载到后端(C#)中,每个嵌套实体不一定有所有级别的.Include()来带回FULL对象,因为每个Task都有自己的实体/集合,这些实体/集合不需要这些组件。
在我们的Task实体中,我们有一个Event的集合。(因此,Spacecrafts有一个包含EventsTasks的集合。)我们在Spacecraft上没有单独的后端模型属性Events[]。当我们为这个组件提取Spacecraft查询时,我们不包括Events,它将嵌套在每个Spacecraft的Tasks中。这样做真的会对速度产生影响,而且我们以前还没有需要自己访问航天器的事件。我们有单独的服务来获取航天器的Tasks[],然后我们将其包含在Events[]中。
最近,我们有一个任务,要显示列表组件中spacecraft的所有Tasks之间存在的所有Events的COUNT,分为3个类别的Severity。我们有一个单独的http方法,它允许我们从数据库中获取所有Event,其属性spacecraftId与给定spacecraft的id匹配,而不必在LINQ查询中深入3层,返回不需要的信息并浏览航天器的任务。这在应用程序的每个其他领域都能完美工作。
我目前正在做的是将我的航天器列表加载到我的list组件中,然后使用一个循环进行单独的调用以获得每个航天器的Events[],并将每个响应Map到航天器模型的FRONT END only属性'Events[]'(我为此任务添加的)。
一旦通过Input()接收到Events[]数据,就可以在子组件中加载它,但是,当视图在两种视图类型之间翻转时,执行相同的调用来获取每个航天器的Events[]远不是理想的,因为它只是一吨的数据。
理想情况下,我希望将spacecraft[]加载到父组件中,这样我就可以重用相同的数据,而不会有无休止的http调用。我希望这是有意义的。我现在的代码如下,它使用了async/await,它确实工作了。我必须实现async/await,因为子组件在Events[]被返回到它们的spacecraft之前就已经加载了,而且一旦http调用完成,航天器就不会更新。(我也试过设置一个布尔值,在Events[]的最后一次迭代完成时翻转-不起作用!)
列出组件:
公共航天器:int [];

ngOnInit(): void {
  getSpacecraft()
}
getSpacecraft() {
  this.spacecraftService.getSpacecrafts(filters).subscribe(async res => {
      this.spacecrafts = res;
      await this.getSpacecraftEvents();
});
public async getSpacecraftEvents() {
    for (let sp of this.spacecrafts) {
      await this.spacecraftService.getEventsBySpacecraftAsync(sp.id).then(
        res => {
          sp.Events = [...res];
        }
      )
    };
    this.isLoading = false;
}

服务方式:

getEventsBySpacecraftAsync(spacecraftId: string): any {
    let params = {
      withDetails: false
    };
    return this.http.get<any>(`${this.endpoint}/${spacecraftId}/Events`, { params: params    }).toPromise();
  }

我不一定喜欢这样,因为控制视图的组件需要等待另一个组件代表它们同步解析数据。我真的在尝试利用任何RxJs功能,以便在组件中接触数据之前将这些额外的Event调用完全提取到服务层中,但我不确定该如何处理它。有没有更好的办法?(当然,即使不是RxJs)。我不能使用解析器-这是我尝试的另一种方法。
而且,是的,我100%考虑采用一个新的后端流程,让航天器的Events[]在初始的http调用中到达,但我真的很想看看除了async/await之外是否还有其他选项。

vdzxcuhz

vdzxcuhz1#

我可以想到两种方法来做到这一点:您可以创建一个中间组件,用于加载事件数据并在网格和列表组件之间切换,而无需在每次切换视图时调用服务器,或者,您可以使用map迭代所有航天器并将事件数据附加到它们,例如:

this.spacecraftsService.getSpacecrafts()
.pipe(map(spacecrafts: Spacecraft[] => {
    spacecrafts.map(spacecraft: Spacecraft => {
        const events = /* some logic to fetch the events */
        return { ...spacecraft, events } 
    })
}))

根据您对RxJS的了解程度,第二种方法有更有效的方法,但这说明了这一点。

9ceoxa92

9ceoxa922#

首先,如果没有必要,我建议你不要把承诺和可观察到的东西混在一起。如果可以的话,最好还是用Angular 来观察。因此,我将从getEventsBySpacecraftAsync中删除async,并使其返回observable:

getEventsBySpacecraft(spacecraftId: string): any {
    let params = {
      withDetails: false
    };
    return this.http.get<any>(`${this.endpoint}/${spacecraftId}/Events`, { params: params    });
  }

现在在getSpacecraftEvents中,您实际上是在一个接一个地调用许多事件。等待for循环中的每个调用。相反,您可以同时进行这些调用,这将大大加快此过程。此外,由于我们在服务中切换到可观测数据,我们在这里也这样做:

public getSpacecraftEvents() {
  forkJoin(
     this.spacecrafts.map(sp => this.spacecraftService.getEventsBySpacecraft(sp.id)))
    .subscribe(events => sp.Events = events);
  this.isLoading = false;
}

代替for循环,我们将航天器数组Map到可观测量数组,并使用forkJoin将它们连接在一起。订阅后,他们同时被要求。
它仍然不是完美的,因为它不是在你获取航天器后等待,而是在单独的订阅中完成的。因此,让我们进一步修复它,我们将使它成为一个返回observable但不订阅它的方法,稍后我们将在getSpacecraft()中使用它。

public getSpacecraftEvents() {
  return forkJoin(
    this.spacecrafts.map(sp => this.spacecraftService.getEventsBySpacecraft(sp.id)));
}

getSpacecraft方法:

getSpacecraft() {
  this.spacecraftService.getSpacecrafts(filters)
    .pipe(switchMap(spacecrafts => {
      this.spacecrafts = spacecrafts;
      return this.getSpacecraftEvents()
    })).subscribe(events => {
      this.spacecrafts.foreach((sp, idx) => {
        this.spacecrafts[idx].events = events.filter(e => e.spacecraftId === sp.id);
      });
    });

现在使用switchMap,我们将两个系列的调用加入到一个可观察对象中,该对象在一个订阅中执行。和事件调用将同时执行。

相关问题