setTimeOut()在Angular生命周期挂钩中重复:ngDoCheck,ngAfterContentChecked,ngAfterViewChecked

时间:2018-07-13 23:12:27

标签: angular settimeout

可重复性

我有一个小的TypeScript代码片段,如下所示:

ngAfterViewChecked(){
    console.log("ngAfterViewChecked 1");
    setTimeout(() => {
      console.log("ngAfterViewChecked 2");
    }, 1000);
  }

函数setTimeOut()应该在1秒钟后得到lambda函数,然后然后停止。但是,钩子ngAfterViewChecked()被连续调用(摘自Chrome开发者工具控制台):

00:36:50.827 home.component.ts:53 ngAfterViewChecked 1
00:36:51.842 home.component.ts:55 ngAfterViewChecked 2
00:36:51.843 home.component.ts:53 ngAfterViewChecked 1
00:36:52.843 home.component.ts:55 ngAfterViewChecked 2
00:36:52.844 home.component.ts:53 ngAfterViewChecked 1
00:36:53.845 home.component.ts:55 ngAfterViewChecked 2
00:36:53.846 home.component.ts:53 ngAfterViewChecked 1
00:36:54.848 home.component.ts:55 ngAfterViewChecked 2
...

没有setTimeOut(),函数ngAfterViewChecked()仅被调用一次。 ngDoCheck()ngAfterContentChecked()也会发生此问题。

使用其他Angular生命周期挂钩进行测试

setTimeOut()constructor()ngOnInit()ngAfterContentInit()中声明的相同代码体,有无 ngAfterViewInit(),被调用一次,如预期。

环境

  • 该程序非常简单(例如Angular的“ Hello World”)。没有第三方图书馆。
  • Angular 5和6都有此问题(尚未测试较低版本)。它们分别安装在不同的计算机上。

    Angular CLI: 6.0.8
    Node: 8.11.3
    OS: win32 x64
    Angular: 6.0.9
    
    
    Angular CLI: 1.7.4
    Node: 8.11.1
    OS: win32 x64
    Angular: 5.2.10
    
  • Windows 8.1 x64。

  • Google Chrome 67(64位)。

我的猜测

钩子constructor()ngOnInit()ngAfterContentInit()ngAfterViewInit()在组件的整个生命周期中都会被调用一次,无论其内容在整个生命周期中是如何演变的。因此,这些钩子根本不会发生此问题。

使用ngDoCheck()ngAfterContentChecked()ngAfterViewChecked(),当Angular 检测到更改时它们会被调用。但是,如lambda函数主体所示,仅使用简单的console.log()。我认为Angular可能会拦截setTimeOut()调用,并盲目地相信可能会有一些更改,因此它启动了更改检测过程,这导致了我们所看到的:调用无限链接

问题

这是错误还是功能?

1 个答案:

答案 0 :(得分:3)

功能-异步操作完成后(例如setTimeout),将运行Angular的更改检测-因此setTimeout本身会导致ngAfterViewChecked运行,反之亦然。

如果您不希望发生这种情况,则可以在Angular区域之外运行事情。

   ngAfterViewChecked(){
    console.log("ngAfterViewChecked 1");

    this.ngZone.runOutsideAngular(() => {
      setTimeout(() => {
        console.log("ngAfterViewChecked 2");
      }, 1000);
    });
  }

您可以在构造函数(即private ngZone: NgZone)中注入NgZone。查看Angular和zone.js之间的关系以获取更多信息。