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

Problem with calling multiple asynchronous functions in ngOnInit

下午好,

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

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

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

我怎样才能在这里前进?我可以使这些函数调用同步吗?我能以某种方式将它们链接在一起吗?

感谢任何帮助。

相关代码如下:

NGONINIT 和三个函数:

  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 应该保持不变并表示数据库中的内容,因此我稍后可以在两者之间进行比较。

希望这是清楚的。

提前致谢。

您可以使用 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。您可能需要在订阅中添加一个值检查以确保您拥有所需的值,但文档说:

This operator is best used when you have a group of observables and only care about the final emitted value of each.

如果您的 html 取决于您的方法检索的数据,您将不得不对其进行调整,例如通过添加加载程序来等待订阅结束,因为它是异步的。

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

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

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

万一有人看到@Quentin 的上述回答,我想我会 post 我最终使用的代码按预期工作,我感谢 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`);
  }

辅助方法不相关,因为它们只是处理提供的数据。