在 Angular 10 中的 ngOnInit() 之后执行某些逻辑
Execute certain logic exactly after ngOnInit() in Angular 10
我想在 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
总是 'undefined'.
我尝试将代码块从 ngAfterViewInit()
放到 ngOnInit()
,在 promise 调用之后,
itemFound
会得到正确的值。
谁能帮忙解释一下哪里出错了?是因为 Promise 调用是异步的吗?
因为localDataService.getData
和remoteDataService.getData
都是异步的,所以不确定哪个先解决,localDataService.getData
可能在ngOnInit
有的时候没有解决完成。
所以即使你在ngOnInit
完成后立即调用remoteDataService.getData
,当remoteDataService.getData
被解析时,也不确定localDataService.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
}
}
}
According to Angular lifecycle hooks, the ngAfterViewInit() should be execute after ngOnInit(),
是。
but the code running result tells otherwise.
没有。您不是在 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
});
}
我通过 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
}
})
}
}
}
我想在 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
总是 'undefined'.
我尝试将代码块从 ngAfterViewInit()
放到 ngOnInit()
,在 promise 调用之后,
itemFound
会得到正确的值。
谁能帮忙解释一下哪里出错了?是因为 Promise 调用是异步的吗?
因为localDataService.getData
和remoteDataService.getData
都是异步的,所以不确定哪个先解决,localDataService.getData
可能在ngOnInit
有的时候没有解决完成。
所以即使你在ngOnInit
完成后立即调用remoteDataService.getData
,当remoteDataService.getData
被解析时,也不确定localDataService.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
}
}
}
According to Angular lifecycle hooks, the ngAfterViewInit() should be execute after ngOnInit(),
是。
but the code running result tells otherwise.
没有。您不是在 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
});
}
我通过 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
}
})
}
}
}