ng zone

背景

众所周知, change detect要解决的事情,就是数据变化 触发 视图变化,而最常见的两个问题是如何探测变化,和如何减少不必要的更新

vue用修改getter/setter或proxy的方式 来完成依赖收集和变化通知,使用lazy watcher来减少更新

svelte 采用编译时更改代码的行为, 避免检测

react 采用setState函数调用 和 队列控制批量更新

那ng呢

NgZone

ng: 什么时候会有视图更新

  • 用户的操作事件: click/change/input
  • 去后台请求响应后
  • Timers:

zone.js 能够维持运行时上下文, zone有生命周期钩子, 且Monkey-patched了一些方法(setInterval,alert,prompt,addEventListener,removeEventListener)

NgZone, 提供 run(callback)/runOutsideAngular(callback), 分别用于当三方api中的异步回调想要修改内容时触发检查,和普通的操作中希望避开检查

你还可以设置 ChangeDetectionStrategy.OnPush, 手动触发更新检查

你也可以动态的通过ChangeDetectorRef进行检查的启用和停用

甚至你可以 通过 module 中 { ngZone : 'noop'} 去一定层级禁用它,然后自己实现响应式都可以

而react是把数据与视图绑定的叫做state,没绑定的叫做ref

总结一下

以渲染10000个可以draggle的svg作为例子, 通过cdr并不能完全避免检测,因为你的mouse move也会触发检测,只是没有变化发生而已

而通过在mouseDown中的runOutsideAngular中给mousemove绑定,就可以实现mouse move 也不触发检测, 再在mouseUp中移除监听,并且通过this.zone.run触发更新检测

而对于多个异步的调用过程,在zone的加持下也容易看到调用的“栈结构”

参考

youtube zone

https://github.com/angular/angular/tree/main/packages/zone.js

https://angular.io/guide/zone

https://angular.io/api/core/ChangeDetectionStrategy

https://angular.io/api/core/ChangeDetectorRef