0

我想在之后执行一些逻辑,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(),但代码运行结果表明并非如此。itemFoundinngAfterViewInit()始终是“未定义的” 。

我试图将代码块从ngAfterViewInit()to ngOnInit(),在 promise 调用之后,itemFound将获得适当的值。

谁能帮忙解释哪里出了问题?是因为 Promise 调用是异步的吗?

4

3 回答 3

2

根据 Angular 生命周期钩子,ngAfterViewInit() 应该在 ngOnInit() 之后执行,

这是。

但代码运行结果另有说明。

它没有。您不是在 中分配列表ngOnInit,而是在承诺回调中分配列表。一旦 promise 得到解决,该回调将被调用,但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
  });
}
于 2021-03-29T05:53:49.863 回答
1

因为localDataService.getDataremoteDataService.getData都是异步的,所以不确定哪个会先解决,localDataService.getData可能在完成的时候还没有解决ngOnInit

所以即使你调用remoteDataService.getData刚刚ngOnInit完成后,也不确定是否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      
    }
  }

}
于 2021-03-29T05:53:28.763 回答
0

BehaviorSubject通过Rxjs lib 实现了这一点,这基本上是一种可观察的模式。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

       }
      })

    }
 }

}
于 2021-03-29T16:13:42.447 回答