我有一个小的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()
也会发生此问题。
在setTimeOut()
,constructor()
,ngOnInit()
,ngAfterContentInit()
中声明的相同代码体,有无 ngAfterViewInit()
,被调用一次,如预期。
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。
钩子constructor()
,ngOnInit()
,ngAfterContentInit()
,ngAfterViewInit()
在组件的整个生命周期中都会被调用一次,无论其内容在整个生命周期中是如何演变的。因此,这些钩子根本不会发生此问题。
使用ngDoCheck()
,ngAfterContentChecked()
和ngAfterViewChecked()
,当Angular 检测到更改时它们会被调用。但是,如lambda函数主体所示,仅使用简单的console.log()
。我认为Angular可能会拦截setTimeOut()
调用,并盲目地相信可能会有一些更改,因此它启动了更改检测过程,这导致了我们所看到的:调用无限链接。
这是错误还是功能?
答案 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之间的关系以获取更多信息。