这篇我们再次聊聊 Angular 的 CD
Zone vs ngZone
- zone.js, 它是 js 异步执行的上下文。凡事通过
zone.run(func)
,都是在 zone 的上下文中。
zone.js, 它通过封装了一些常见的异步操作的方法,例如 setTimeout/xhr/promise/onxxxlist,我们一旦嵌入 zone.js 到我们的代码中,凡是调用如上异步的方法,其实调用的都是 zone 封装的这些方法,从而达到对这些方法进行接管,类似于后端里面的 AOP, 推荐两个链接了解 zone link1, link2 - ngZone, Angular 是继承于 zone.js,同时提供了实现的三个 HookAPI, 那么 Angular 是如何激发 CD,其实它在
onTurnDone()
这个 HookAPI 里面做的。- onTurnStart()
- onTurnDone() 当异步事件执行结束,同时所有的 MicroTask 执行结束后,emit 这个事件。
- onEventDone()
这里提供一个简单的代码
class ApplicationRef {
changeDetectorRefs:ChangeDetectorRef[] = [];
constructor(private zone: NgZone) {
this.zone.onTurnDone
.subscribe(() => this.zone.run(() => this.tick());
}
tick() {
this.changeDetectorRefs
.forEach((ref) => ref.detectChanges());
}
}
总结一下,也就是说,Angular 通过 ngZone,以及继承来的 zone,对于所有的异步操作,例如,setTimeout/Promise/onxxx/xhr, 都会有感知,然后,在这些异步方法执行结束后,在onTurnDone()
钩子里面激发整个 VDomTree 做更新检测。
- 那么同样的对于mousemove这种事件,很容易造成性能问题,ngZone提供了两种方式,来规避这个问题
ngZone.runOutofAngularZone(func)
,ngZone.run(func)