Angular Change Detection

·  阅读 293

什么是change detection

当浏览器界面已经渲染完成,用户触发的一些event或一些异步的数据请求,可能会引起了系统中数据的变化;这种情况下,如果我们需要根据数据变化更新DOM会很麻烦,遍历整个DOM树的开销很大,因此我们需要在找到变化的内容的情况下,尽可能缩小对应更新的DOM范围。
在angualr应用中,变化检测就是为了是获取程序中数据元素的状态,并把状态的变化显示在用户界面上。通过变化检测机制可以即时的根据数据变化,对DOM进行更新。

哪些行为会引起change?

通常情况下,以下三种异步行为会引发状态的变化:

  1. Events : input, click, drag, drop…
  2. 异步数据请求
  3. setTimeout() & setInterval()

change发生后,如何通知angular及时更新view?

angular内部提供了一个ApplicationRef类,在该类中对ngZone的onTurnDone事件进行了监听。异步的事件都会触发ngZone中的hook,每当onTurnDone触发,都会调用detectChanges方进行变化检测。

Change Detection

angular中的每一个component都有自己的change detector(变化检测器),这使我们可以独立控制每一个组件的变化检测的机制和时间。

试想,当我们在某个子组件触发了一个event,绑定在zone上的事件处理程序被触发,它通知angular执行变化检测。

Angular 中,一个个component 组成了一整个component tree的结构,每个component都拥有自己的change detector,因此不难想象也存在一个change detector tree,与数据从上到下的单向传递一致,每个组件的变化检测也是从跟组件开始的。

优化Change Detection

Angular默认会在事件发生时,依次检查每个组件的变化;虽然变化检测的速度很快,但如果能够通知Angular只对某部分进行变化检测,必然会更高效。

合理的通过使用Immutability和Observables可以帮我们实现部分检测。

1. Immutability - 不变的数据

  • 什么是Mutability
    想要搞清楚什么使Immutability 的数据,先来看一下什么叫Mutability。
    比如我们有一个parent component和一个child component,父向子中传递一个mData,mData是一个Object,包含name和email两个属性;
    当父组件中的changeData方法时,mData中的name发生了变化,但mData对象的引用并没有变;
    虽然Object对象自身没有发生变化,但name属性变了,Angular仍然需要需要对该Object进行变化检测。

       @Component({
         template: '<child [mData]="mData"></child>'
       })
       class ParentComponent {
           constructor() {
               this.mData= {
                 name: 'Christoph Burgdorf',
                 email: 'christoph@thoughtram.io'
               }
           }
       	changeData() {
               this.mData.name = 'Pascal Precht';
           }
       }    
    复制代码

    Object是一种典型的Mutability数据,即使Object自身不发生改变,它的某些属性也可能会发生变化,Angular为了及时的更新这些变化,不得不在每次event发生时,对Object进行变化检测。

  • Immutability Object
    我们应尽可能地使用Immutability Object,这意味着我们每次需要改变Object时,由于原对象是不可改变的,我们必须要改变该对象的引用。这样,Angular则不需要在每次event触发时对Object进行检测,而仅是在Object的自身变化时进行。

  • 减少变化检测的次数
    Angular为我们提供了一种机制[changeDetection: ChangeDetectionStrategy.OnPush],可以指定当组件仅在Input的对象发生变化时,运行该组件的变化检测。
    结合Immutability Object,在父组件中我们定义Immutability Object传入子组件,在子组件内使用ChangeDetectionStrategy.OnPush;这样,父组件对应的事件触发必然会改变Immutability Object的引用,子组件则只会在Input的引用改变时进行变化检测;通过这种方式,能够有效的减少了不需要的变化检测。

2. 利用Observables进行数据传递

将Input的变量定义为Observable。虽然Observable对象中的数据流的变化,并不改变对象的引用,但是,通过对Observable对象的订阅,可以及时的从子组件中得到父组件的变化;结合changeDetection: ChangeDetectionStrategy.OnPush,也能对变化检测进行优化。

    @Input() booksList: Observable<any>;
    
    ngOnInit() {
        // 在子组件中对booksList对象进行订阅
        this.booksList.subscribe(books=>{
           console.log(books); 
        })
    }复制代码
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改