在 ngOnInit 中调用多个异步函数的问题

Posted

技术标签:

【中文标题】在 ngOnInit 中调用多个异步函数的问题【英文标题】:Problem with calling multiple asynchronous functions in ngOnInit 【发布时间】:2020-11-07 16:34:55 【问题描述】:

下午好,

我正在努力在 ngOnInit 中放置函数。如果我正确理解出了什么问题,问题似乎是当我在 ngOnInit 中放置异步函数并且下一个函数取决于第一个的完整执行时,如果第一个尚未完成,那么我需要的数据仍然是未定义,它将失败。

我想做的很简单,真的。 ngOnInit 通过查询我的 API 来填充两个数组。一个是与用户关联的组,另一个是所有组(这些来自数据库)。然后它将通过比较这两个数组来填充第三个数组(allgroups - groups associated = groupsavailable)。

在初始填充之后,我希望能够根据用户交互在数组之间进行进一步比较。这些功能有效,但大约 10% 的情况下,我会收到一个未定义的问题,可以通过刷新页面(有时是两到三遍)来解决。这向我表明这是一个操作顺序的问题。

我该如何继续前进?我可以使这些函数调用同步吗?我可以以某种方式将它们链接在一起吗?

感谢您的帮助。

相关代码如下:

NGONIT 和三个函数:

  ngOnInit(): void 
    this.populatePickListUserAssociatedGroups();
    this.populateOriginalUserAssociatedGroups();
    this.populateAvailableGroups();
  
  // METHODS
  private populatePickListUserAssociatedGroups = () => 
    this.userDataService.getSingleUserAssociatedGroups()
      .then(groups => this.pickListUserAssociatedGroups = groups)
      .then(groups1 => this.originalUserAssociatedGroups = groups1);
  
  private populateOriginalUserAssociatedGroups = () => 
    this.userDataService.getSingleUserAssociatedGroups().then(groups => this.originalUserAssociatedGroups);
  
  private populateAvailableGroups = () => 
    this.userDataService.getAllGroups()
      .then(groups => this.allGroups = groups)
      .then(groups => groups.filter(i1 => !this.originalUserAssociatedGroups
        .some(i2 => i1.id === i2.id)))
      .then(groups => this.availableGroups = groups);
  

我已经描述了我的主要问题,但我还有另一个问题。由于某种原因,这两个数组:pickListUserAssociatedGroups 和 originalUserAssociatedGroups 总是一起变化。这违背了目的。选择列表数组表示用户更改的内容(我正在使用 ngPrime 选择列表),而 originalUserAssociatedGroups 应该保持不变并表示数据库中的内容,因此我可以稍后在两者之间进行比较。

希望这很清楚。

提前致谢。

【问题讨论】:

在 Angular 中使用 Rxjs 运算符而不是 Promise。使用运算符让您的生活更轻松。 【参考方案1】:

您可以通过使用 rxjs 来实现。您的问题有多种解决方案,但我认为最好使用forkJoin。以下是您可以实现的方法:

ngOnInit() 
    forkJoin(
      this.populatePickListUserAssociatedGroups(),
      this.populateOriginalUserAssociatedGroups(),
    ).subscribe(finalResult => 
      // do your things with finalResult[0] and finalResult[1]
      this.populateAvailableGroups();
    );
  

  populatePickListUserAssociatedGroups(): Observable<any> 
    return this._myService.getPickListUserAssociatedGroups();
  

  populateOriginalUserAssociatedGroups(): Observable<any> 
    return this._myService.getOriginalUserAssociatedGroups();
  

  populateAvailableGroups() 
    // your code
  

请注意,我使用 observable,而不是 promise。您可能需要在订阅中添加值检查以确保您拥有所需的值,但文档说:

当您有一组可观察对象并且只关心每个对象的最终发射值时,最好使用此运算符。

如果您的 html 依赖于您的方法检索的数据,则您必须对其进行调整,例如添加一个加载器,以等待订阅结束,因为它是异步的。

最后,你的服务方法应该返回一个 observable,你可以通过简单地返回响应来做到这一点:

myServiceMethod(): Observable<any> 
  return this._http.get<Whatever>(url);

对于您的其他问题,如果选择列表数组的更改是在您的构造函数中本地进行的,那么您只需将其存储在 forkJoin 订阅中的变量中: this.mypickListArray = finalResult[0] 并使用它。

【讨论】:

非常感谢。正如 Sunny Goel 上面所说的那样,从根本上来说,从承诺的角度来处理这个问题似乎并不是最好的方法。我已经用 observables 做了一些工作,但还不够。我想我必须先离开并花一些时间来处理这些想法,然后才能以一种干净的方式完成我想要的东西。你的例子给了我很多工作。我很感激。我自己有一些资源,但是你有什么建议可以了解 RxJs,特别是它与 HTTP 请求有关的知识吗?当然还有更多... 一般来说理解它的工作原理并不难。将 observable/subscription 过程视为一个流,即您的 observable(此处为 http 调用)和订阅之间的链接。每次更新 observable 时,订阅都会收到更新并运行您放入其中的代码。对于 forkjoin、map、mergemap 等方法,您可以花一些时间在构建良好的文档中查看可能性。我没有来源,因为我只是向谷歌询问我需要什么。我在工作中与 NGRX 合作,这是一个 Angular 的状态管理,它充满了可观察性,所以不妨看看它。 现在,您正在使用 Promise,因此 observable 的概念非常接近它。将 'observable' 替换为 'Promise' 和 'subscribe' 替换为 'then',这是一样的,至少满足您的需求。【参考方案2】:

如果有人从@Quentin 看到上述答案,我想我会发布我最终使用的代码,它按预期工作,我感谢 Quentin 的帮助。

  ngOnInit(): void 
    forkJoin(
      [
        this.populateAllGroups(),
        this.populateAllUserGroup()
      ]
    )
      .subscribe(([x, y]) => 
        this.allGroups = x;
        this.allUserGroupByUser = y;
        this.populateAvailableGroups();
        this.populatePickListUserAssociatedGroups();
      );
  

例如,第一个方法如下所示:

  private populateAllGroups(): Observable<any> 
    return this.userDataService.getAllGroups();
  

而数据服务有这个方法:

  public getAllGroups(): Observable<any> 
    return this.httpClient.get<Group[]>(`$Configuration.userApiURL/getallgroups`);
  

次要方法不相关,因为它们只是操纵提供的数据。

【讨论】:

以上是关于在 ngOnInit 中调用多个异步函数的问题的主要内容,如果未能解决你的问题,请参考以下文章

在 ngOnInit 函数中打开 ng-template 不起作用

等待异步函数在 Angular 中完成

ng4.0 生命周期

自学ng -生命周期钩子

在 ngOnInit Angular 之前处理异步承诺

Angular5服务调用在ngOnInit上不起作用