在 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 中调用多个异步函数的问题的主要内容,如果未能解决你的问题,请参考以下文章