深入理解Angular的变更检测
发布网友
发布时间:2023-03-17 13:51
我来回答
共1个回答
热心网友
时间:2023-05-13 18:27
这是一篇偏理论的文章,Angular的变更检测是这个框架的灵魂,如果我们深入理解这里边的内容,对于优化程序,解决性能问题,以及对Angular的深入理解都有很好的帮助,本文涉及到的知识点主要有: , , 。
Angular有自己的zone,就是我们常见的ngZone,Angular 源码中有一个东西叫做 ApplicationRef,它监听 NgZone 的 onTurnDone 事件。只要这个事件发生,它就执行 函数,这个函数执行变更检查,DOM就会更新,看下图示例,其实zone.js就是 。
在 Angular 中,每个组件都有自己的变更检测器(change detector)。因为我们可以单独控制每个组件的变更检查何时发生以及如何执行,既然每个组件都有自己的 ,并且一个 Angular 应用包含着一个组件树,那么逻辑上我们也有一个 (change detector tree)。这棵树也可以被看成是一个 ,该有向图的数据总是从顶端流向底端(单向数据流)。
其实每个视图(组件)都有一个状态,也是非常重要的角色,因为根据它的值(FirstCheck、 ChecksEnabled、Errored、Destoryed),Angular决定是否对视图及其所有子视图运行或跳过脏值检测。如果ChecksEnabled是false或者视图是Errored或者Destroyed的状态,变更检测将会跳过这个视图以及它的子视图。
此默认策略,就是我们常提到的脏检查,它是只要有变化,就从 根组件 到 所有子组件 进行检查(深度优先遍历)
如上默认的变更检测,Angular必须每次都检测所有组件,但是如果我们可以让Angular仅对应用中发生改变的状态进行变更检测,那样会更高效,一般我们会从下边↓两个方向上着手,实现更加高效且聪明的变更检测。
使用方法如下:
通过引用 ,可以手动去操作变化检测。我们可以在组件中的通过依赖注入的方式来获取该对象:
此变更检测对象提供了如下所示的方法
,那么变化检测不会再次执行,除非手动调用该方法, 在程序中使用this.changeRef.markForCheck() 变化检测,如要想要执行多次多次,则需要多次的运行这句话。具体的执行流程如下:
首先他的使用与是否使用了onPush无关,他是只在当前视图和它的子视图 ,应用场景:明确知道有数据的更新,需要Angular执行变更检测的时候使用。
首先他的使用与是否使用了onPush无关,他是从变化检测树中 ,该组件的变化检测器将不再执行变化检测,同时其子组件也不会执行检测,除非手动调用 reattach() 方法
首先他的使用与是否使用了onPush无关,他是 ,使得该组件及其子组件都能执行变化检测,但是如果当前的组件的父组件 (脏检查)的话,它将 。
当父组件的输入属性是用observable,那么除了使用this.changeRef.markForCheck()来进行变更检测,我们还可以在子组件中使用async pipe, 发出一个新值时,异步管道会将组件标记为要检查更改(其实也是调用了 this.changeRef.markForCheck())
通过一个示例更好的理解这两个方法的区别:
示例解析:
如果大家想真正了解Angular的变更检测,一定要动手写一写相关的demo去验证自己的猜想,否则就像之前的我一样,看了很多理论,还是不能够了解,而且还很容易弄混ChangeDetectorRef的属性~ 希望大家看到这篇文章可以更加清晰点吧~