在 Angular 10 中的 ngOnInit() 之后执行某些逻辑
Posted
技术标签:
【中文标题】在 Angular 10 中的 ngOnInit() 之后执行某些逻辑【英文标题】:Execute certain logic exactly after ngOnInit() in Angular 10 【发布时间】:2021-06-25 04:26:20 【问题描述】:我想在ngOnInit()
之后执行一些逻辑,因为我想将逻辑与页面渲染分离。
我想到了 Angular 生命周期钩子,所以我将逻辑放在 ngAfterViewInit()
中,但似乎它与 ngOnInit()
同时被调用。
代码示例:
export class SampleComponent implements OnInit, AfterViewInit
list = [];
ngOnInit()
this.localDataService.getData().then( res => //Promise call
for (let o in res)
this.list.push(res[o]) //the list get loaded
)
ngAfterViewInit() // the intention is to process the list after it's loaded
this.remoteDataService.getData().then(res =>
for (let o in res)
itemFound = this.list.find( (itemInList) => return itemInList.id === res[o].id)
//and some code to manipulate the item found from list
itemFound = .... // but the itemFound is always 'undefined'
)
根据 Angular 生命周期钩子,ngAfterViewInit()
应该在ngOnInit()
之后执行,但代码运行结果表明并非如此。 ngAfterViewInit()
中的 itemFound
始终为“未定义”。
我尝试将代码块从ngAfterViewInit()
放到ngOnInit()
,在promise 调用之后,
itemFound
将获得适当的价值。
谁能帮忙解释哪里出错了?是不是因为 Promise 调用是异步的?
【问题讨论】:
为什么不创建一个简单的函数并在 getData() 承诺中调用它? 我所做的和你提到的完全一样,但我发现remoteDataService.getData()
的承诺会显着影响页面渲染速度,因为它是一个远程调用并且需要很多时间。这就是我想将它们解耦的原因。
【参考方案1】:
因为localDataService.getData
和remoteDataService.getData
都是异步的,所以不确定哪个会先解决,localDataService.getData
可能在ngOnInit
完成的时候还没有解决。
因此,即使您在ngOnInit
完成后立即调用remoteDataService.getData
,也不确定localDataService.getData
是否在remoteDataService.getData
被解析时被解析。
您必须检查localDataService.getData
和remoteDataService.getData
是否都已解决。一种解决方案如下。
export class SampleComponent implements OnInit, AfterViewInit
localList = [];
remoteList = [];
localListLoaded = false;
remoteListLoaded = false;
ngOnInit()
this.localDataService.getData().then( res => //Promise call
for (let o in res)
this.localList.push(res[o]) //the list get loaded
localListLoaded = true;
manipulate();
);
this.remoteDataService.getData().then(res =>
for (let o in res)
this.remoteList.push(res[o]);
remoteListLoaded = true;
manipulate();
manipulate()
if (localListLoaded && remoteListLoaded)
// some code stuff for remoteList and localList
【讨论】:
我阅读了您和 Meriton 的 cmets,实际上您说的是同样的事情,这也是正确的 - Promise 调用的时间已解决。但是我真的很想在视图初始化之后进行远程调用,这样就不会导致延迟。您的解决方案引发了另一个想法,即变量的侦听器。谢谢!【参考方案2】:根据 Angular 生命周期钩子,ngAfterViewInit() 应该在 ngOnInit() 之后执行,
是的。
但代码运行结果另有说明。
它没有。您不是在ngOnInit
中分配列表,而是在承诺回调中分配列表。一旦承诺得到解决,该回调将被调用,但ngOnInit()
不会等待这种情况发生。 (即使 Angular 想要等待,它也不能等待,因为 Angular 不知道 Promise 对象存在,更不用说您已经向它添加了回调 - 因为等待会冻结 UI,所以 Angular 不想等待)。
如果你想等到两个 Promise 都解决了,你必须问 Promise,而不是 Angular。简单的方法是:
ngOnInit()
Promise.all([
this.localDataService.getData(),
this.remoteDataService.getData()
]).then(([list, data]) =>
// work with list and data
);
【讨论】:
【参考方案3】:我通过 Rxjs 库中的BehaviorSubject
实现了这一点,这基本上是一种可观察的模式。
重点是通知ngAfterViewInit()
中的代码只有在列表数据准备好时才启动。
代码示例:
export class SampleComponent implements OnInit, AfterViewInit
list = [];
private listSub = new BehaviorSubject([]);
listSubObservab = this.listSub.asObservable();
ngOnInit()
this.localDataService.getData().then( res => //Promise call
for (let o in res)
this.list.push(res[o]) //the list get loaded
this.listSub.next(this.list) //notify when list is ready
)
ngAfterViewInit() // the intention is to process the list after it's loaded
this.listSubObservab.subscribe(listLoaded => //observer here, only triggered by notify
this.remoteDataService.getData().then(res =>
for (let o in res)
itemFound = listLoaded.find( (itemInList) => return itemInList.id === res[o].id)
//and some code to manipulate the item found from list
itemFound = .... // Finally the itemFound has proper value
)
【讨论】:
以上是关于在 Angular 10 中的 ngOnInit() 之后执行某些逻辑的主要内容,如果未能解决你的问题,请参考以下文章
在 Angular 5 中的 ngoninit 之后如何运行函数
在哪里订阅 Angular 中的 observable、构造函数或 ngoninit [关闭]