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

因此,即使您在ngOnInit 完成后立即调用remoteDataService.getData,也不确定localDataService.getData 是否在remoteDataService.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      
    
  


【讨论】:

我阅读了您和 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() 之后执行某些逻辑的主要内容,如果未能解决你的问题,请参考以下文章

组件 ngOnInit 中的 Angular 订阅

Angular`ngOnInit`中的异步/等待

在 Angular 5 中的 ngoninit 之后如何运行函数

在哪里订阅 Angular 中的 observable、构造函数或 ngoninit [关闭]

在 angular2 中的 ngOnInit 之后,在构造函数中订阅服务

如何从 ngOnInit Angular 中的服务获取数据