我想在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调用之后,CCD_ 10将得到合适的值。
有人能解释一下哪里出了问题吗?是因为Promise调用是异步的吗?
根据Angular生命周期挂钩,ngAfterViewInit((应该在ngOnInit(
是.
但代码运行结果告诉情况并非如此。
没有。您不是在ngOnInit
中分配列表,而是在promise回调中分配列表。一旦promise得到解决,就会调用该回调,但ngOnInit()
不会等待它发生。(即使angular想等待,它也不能,因为angular不知道Promise对象存在,更不用说你已经向它添加了回调了——而且等待会冻结UI,所以angular不想等待(。
因此,如果你想等到两个承诺都得到解决,你必须询问承诺,而不是棱角分明的承诺。做到这一点的简单方法是:
ngOnInit() {
Promise.all([
this.localDataService.getData(),
this.remoteDataService.getData()
]).then(([list, data]) => {
// work with list and data
});
}
因为localDataService.getData
和remoteDataService.getData
都是异步的,所以不确定哪个先解析,ngOnInit
完成时可能不会解析localDataService.getData
。
因此,即使您在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
}
}
}
我用Rxjslib中的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
}
})
}
}
}