Angular 在应用程序开始时启动两个更改检测周期。
也就是说,它调用了两次Application.tick()方法
1) 引导主组件后 (https://github.com/angular/angular/blob/aaaa34021c2d56f798d20e5a1f31b23972055170/packages/core/src/application_ref.ts#L539-L541)
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 withih 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!!)
因此,您会得到准确的 8 次 serverStatus 重复