我正在学习Udemy的课程: https://www.udemy.com/the-complete-guide-to-angular-2/
我参与了字符串插值的第2.13部分。
作为本课的一部分,您将在组件中定义一个简单函数以显示类的属性之一:
SSL_CTX_set_cipher_list
然后在组件HTML中,将该函数绑定到模板:
export class ServerComponent{
serverId = 10;
serverStatus = 'offline';
getServerStatus(){
return this.serverStatus;
}
}
我要测试的是将字符串插值标签绑定到自引用函数时发生的情况。例如:
<P>Server with ID {{ serverId }} is {{ getServerStatus() }}</P>
运行此代码时,我注意到页面显示以下内容:
getServerStatus(){
this.serverStatus = this.serverStatus + this.serverStatus;
return this.serverStatus;
}
准确重复8个serverStatus变量。
我想知道的是为什么这个数量恰好是8次重复?八次重复后,angular使用哪种逻辑来确定“实时”模板指令与class属性无关。
答案 0 :(得分:3)
角度启动在应用程序开始时两个变更检测周期。
换句话说,它两次调用Application.tick()
方法
private _loadComponent(componentRef: ComponentRef<any>): void {
this.attachView(componentRef.hostView);
this.tick();
2)并且在第一个VM转弯时(当zonejs中没有微任务时)(https://github.com/angular/angular/blob/aaaa34021c2d56f798d20e5a1f31b23972055170/packages/core/src/application_ref.ts#L385-L386)
this._zone.onMicrotaskEmpty.subscribe(
{next: () => { this._zone.run(() => { this.tick(); }); }});
考虑到这一点,让我们回到我们的Application.tick()方法。它在视图树(组件视图或嵌入式视图)上运行更改检测。
tick(): void {
...
try {
...
this._views.forEach((view) => view.detectChanges());
if (this._enforceNoNewChanges) {
this._views.forEach((view) => view.checkNoChanges());
}
} catch (e) {
...
} finally {
...
}
}
我们在这里能注意到什么?
我们注意到在开发模式下(因为this._enforceNoNewChanges = isDevMode();
https://github.com/angular/angular/blob/aaaa34021c2d56f798d20e5a1f31b23972055170/packages/core/src/application_ref.ts#L383) Angular运行两次更改检测周期。
这里的另一点是,tick
方法是在try catch
块内执行的。
那么,到目前为止我们有什么?
2 сd cycles * 2 view.detectChanges() on the tree = 4
还在每个view.detectChanges()
上,Angular都会检查模板绑定是否已更改。为此,Angular 执行模板中的每个表达式(因此,您的getServerStatus()
方法将在每次遍历树时执行)。如果在第二个cd withhh tick方法期间绑定发生了一些变化,则Angular会引发错误Expression has changed after it was checked
。如您所料,它不会停止后续的cd循环,谢谢try catch
块。
为简单起见,假设您具有以下模板:
{{ getServerStatus() }}
那这里发生了什么?
Start app serverStatus
loadComponent => tick
|
|__ view.detectChanges()
||
\/
call getServerStatus() 'offlineoffline'
|__ view.checkNoChanges()
||
\/
call getServerStatus() 'offlineofflineofflineoffline'
'offlineoffline' !== 'offlineofflineofflineoffline'
||
\/
ExpressionChangedAfterItHasBeenCheckedError (template is not updated!!)
onMicrotaskEmpty => tick
|
|__ view.detectChanges()
||
\/
call getServerStatus() 'offline'.repeat(8)
|__ view.checkNoChanges()
||
\/
call getServerStatus() 'offline'.repeat(16)
'offline'.repeat(8) !== 'offline'.repeat(16)
||
\/
ExpressionChangedAfterItHasBeenCheckedError (template is not updated!!)
结果,您得到了serverStatus
的精确8次重复