为什么在设置了OnPush标志的情况下,Angular2在更改检测过程中同时捕捉到引用更改和基元更改
Why is both reference change and primitive change catch by Angular2 during change detection even with OnPush flag set?
考虑以下代码
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;
}
}
从我做的实验来看,以下是我对当前Angular2
变化检测策略的理解,有人能验证它是否属实吗?
Angular2在进行更改检测时默认检查值是否相等。如果不存在
ChangeDetectionStrategy.OnPush
,则检查组件树中的每个关注变量的值是否相等。如果值相等为false,则会重新提交该特定组件;如果值相等值为true,则不会重新提交该具体组件。如果将
ChangeDetectionStrategy.OnPush
添加到零部件中。行为变化如下i。如果组件内的变量发生参考变化,则重新绘制组件,并检查子组件的变化检测(其具体的变化检测算法值/参考检查取决于
ChangeDetectionStrategy.OnPush
)ii。如果组件内的变量没有参考变化,则不重新绘制组件,并且不检查子组件的变化检测,无论是否存在
ChangeDetectionStrategy.OnPush
这是正确的解释吗?
我重新设计了你的plunker:新的plunker
由于基元值是不可变的,因此重新分配和更新之间没有区别–基元获得了新的不可变值,所以我删除了"更新"代码。此外,将分配一个新的对象引用(它确实会触发变化检测)和分配一个新基元值(它不会触发变化检测。所以我也这么做了。
如果你运行我的Plunker,我们可以进行以下观察:
- 更改
OnPush
组件上的引用类型的输入属性将更新组件的视图。将检查模板绑定是否有更改。此外,还会检查子组件(假设它们未使用OnPush
) - 更改
OnPush
组件上引用类型中包含的基元属性将不会更新组件的视图。不检查模板绑定是否有更改。此外,无论是否使用OnPush
,都不会检查子组件 ngDoCheck()
总是在第一个OnPush
组件上调用,而不管是否检查模板绑定的更改。我觉得这很奇怪(谁知道呢,也许是个bug)。因此,仅仅因为调用了ngDoCheck()
并不一定意味着检查了模板绑定
请注意,当检测到模板绑定更改时,只有该更改才会传播到子组件或DOM(视情况而定,具体取决于绑定类型)。如果绑定更改导致DOM更改,则不会重新绘制整个组件。只有绑定的DOM数据才会更新,浏览器才会更新这一个DOM元素。(这与其他一些框架不同,在其他框架中,如果发现任何更改,它们会重新提交整个模板。这有助于提高Angular的速度。)
这篇文章非常详细地解释了它:
http://victorsavkin.com/post/133936129316/angular-immutability-and-encapsulation
简而言之,你的假设是正确的。Angular2必须是保守的,并检查值是否相等,即它必须对引用的对象进行"深度检查"。
使用ChangeDetectionStrategy.OnPush
,只有当对其输入对象的引用发生更改时,才会更新组件。
这就是为什么不可变对象可以是首选的数据结构——如果我们必须更新一个对象,那么组件现在正在引用一个新对象。因此,angular很容易知道哪些组件必须更新。
通过ChangeDetectorRef.markForCheck();
方法,性能行为也可以通过可观察性来实现。
这里对此进行了解释:
http://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html
- 引用对象中的通用值
- 如何引用HTML中节点模块中的js文件
- 为什么我可以引用Javascript中尚未定义的变量
- 在提交过程中使用同步确认灯箱提交表格
- 在电子商务结账过程中显示特定于上下文的错误
- 引用Javascript中的索引集合
- 通过引用Javascript中的另一个函数来传递对象方法
- Grunt排除在生成过程中插入某些文件
- JavaScript:如何在迭代过程中修改数组中的值
- 如何检查是否存在“;没有到主机的路由”;在流式传输视频的过程中一遍又一遍
- 在asp.net页面中显示javascript执行过程中的加载图标
- 在网格视图的自动刷新过程中,设置内部网格视图文本框的可见性
- ng-show内容在页面加载过程中闪烁,尽管它不是真实的,并且ng-cloak不适用于FF
- 如何在初始化过程中引用同一对象内的对象字段
- Python Javascript哈希库,以确保JSON对象在传输过程中不会损坏
- 如何将SignalR包含在gullow构建过程中
- 如何在剑道网格中直观地识别拖放过程中的放置目标
- 我是否可以在渲染过程中使用三.js合并每一帧中的几何体
- 为什么在设置了OnPush标志的情况下,Angular2在更改检测过程中同时捕捉到引用更改和基元更改
- 如何在创建过程中引用同一个对象的属性?