为什么即使设置了OnPush标志,在更改检测期间Angular2会引用参考更改和原始更改?

时间:2016-04-18 19:13:32

标签: javascript typescript angular angular2-changedetection

考虑以下code

2.0.3

根据我的实验,这是我对当前import {Component, OnInit, Input, OnChanges, DoCheck, ChangeDetectionStrategy} from 'angular2/core' @Component({ selector: 'child1', template: ` <div>reference change for entire object: {{my_obj1.name}}</div> <div>reassign primitive in property of object: {{my_obj2.name}}</div> <div>update primitive in property of object: {{my_obj2.num}}</div> `, changeDetection: ChangeDetectionStrategy.OnPush }) export class Child1 { @Input() my_obj1: Object = {'name': ''}; @Input() my_obj2: Object = {'name': '', 'num': 0}; ngDoCheck() { console.log('check from child1'); console.log(this.my_obj1); console.log(this.my_obj2); } } @Component({ selector: 'parent', template: ` <div> <child1 [my_obj1]="my_obj1" [my_obj2]="my_obj2" > </child1> <button (click)="change_obj1()"> Change obj1 </button> </div> `, directives: [Child1] }) export class App { my_obj1: Object = {'name': 'name1'}; my_obj2: Object = {'name': 'name2', 'num': 0}; change_obj1() { this.my_obj1 = {'name': 'change1'} this.my_obj2['name'] = 'change2'; this.my_obj2['num'] += 1; } } 更改检测策略的理解,有人可以验证它是否真实?

  1. Angular2默认情况下在进行更改检测时检查值是否相等。如果没有Angular2,则检查组件树中的每个监视变量的值是否相等。如果值相等为false,则该特定组件将被重新呈现,如果值相等则为true,则该特定组件将不会被重新呈现。

  2. 如果您将ChangeDetectionStrategy.OnPush添加到组件中。行为更改如下

    我。如果组件内的变量具有引用更改,则重新呈现该组件,并检查子组件的更改检测(其特定的更改检测算法值/引用检查取决于ChangeDetectionStrategy.OnPush

    II。如果组件内部的变量没有引用更改,则不会重新呈现该组件,并且不检查子组件的更改检测,无论是否存在ChangeDetectionStrategy.OnPush

  3. 这是正确的解释吗?

2 个答案:

答案 0 :(得分:4)

我稍稍改造了你的傻瓜:new plunker

由于原始值为immutable,重新分配和更新之间没有区别 - 原语获取新的不可变值,因此我删除了“更新”代码。此外,拆分分配新的对象引用(触发更改检测)和分配新的原始值(不触发更改检测)非常有用。所以我也这样做了。

如果您运行我的Plunker,我们可以进行以下观察:

  1. OnPush组件上更改引用类型的输入属性 将更新组件的视图。检查模板绑定的更改。此外,还会检查子组件(假设它们未使用OnPush)。
  2. 更改OnPush组件上的引用类型中包含的原始属性不会更新组件的视图。不检查模板绑定的更改。此外,不检查子组件,无论它们是否使用OnPush
  3. ngDoCheck()始终在第一个OnPush组件上调用,无论是否检查模板绑定是否发生更改。我发现这很奇怪(谁知道,也许这是一个错误)。因此,仅仅因为调用ngDoCheck()并不一定意味着检查模板绑定。
  4. 注意,当检测到模板绑定更改时,只将该更改传播到子组件或DOM(视情况而定,具体取决于绑定类型)。如果绑定更改导致DOM更改,则不会重新呈现整个组件。只更新了绑定的DOM数据,浏览器才会更新那个DOM元素。 (这与其他一些框架不同,如果发现任何更改,它们会重新渲染整个模板。这有助于使Angular更快。)

答案 1 :(得分:0)

这篇文章详细解释了它:

http://victorsavkin.com/post/133936129316/angular-immutability-and-encapsulation

简而言之,您的假设是正确的。 Angular2必须保守并检查价值相等,即它必须进行深度检查&#39;引用的对象。

使用ChangeDetectionStrategy.OnPush时,只有在对其输入对象的引用发生更改时才会更新组件。

这就是为什么不可变对象可以是首选数据结构 - 如果我们必须更新对象,该组件现在引用一个新对象。因此,角度很容易知道哪些组件必须更新。

通过ChangeDetectorRef.markForCheck();方法,可以通过观察者实现高性能行为。

这在此解释:

http://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html