在 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.getDataremoteDataService.getData都是异步的,所以不确定哪个先解决,localDataService.getData可能在ngOnInit有的时候没有解决完成。

所以即使你在ngOnInit完成后立即调用remoteDataService.getData,当remoteDataService.getData被解析时,也不确定localDataService.getData是否被解析。

您必须检查 localDataService.getDataremoteDataService.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

       }
      })

    }
 }

}