这篇我们再次聊聊 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)