Angular 重新绘制dom的角度变化检测过程

Angular 重新绘制dom的角度变化检测过程,angular,angular2-changedetection,Angular,Angular2 Changedetection,我正在学习角度变化检测过程,我正在检查Chrome开发工具,我看到奇怪的行为 我的plnkr演示了以下行为: 我有一个简单的组件视图: <li *ngFor="let item of list">{{item.name}}</li> 要模拟我添加的简单请求,请执行以下操作: // simulating request repaint the DOM setInterval( () => { this.list = [{name: 'Gustavo'}, {na

我正在学习角度变化检测过程,我正在检查Chrome开发工具,我看到奇怪的行为

我的plnkr演示了以下行为:

我有一个简单的组件视图:

<li *ngFor="let item of list">{{item.name}}</li>
要模拟我添加的简单请求,请执行以下操作:

// simulating request repaint the DOM
setInterval( () => {
  this.list = [{name: 'Gustavo'}, {name: 'Costa'}];
}, 2000);
如果您注意到,数组
list
会收到一个与初始值相等的列表。让我们想象一下,当Angular在更改检测过程中检查视图中的值时,我们有这样一个代码:

if( oldName !== name )  { // ( 'Gustavo' !== 'Gustavo')
 // update the view
}
但是值是相同的,为什么每隔2秒重新绘制DOM?

但是如果我对对象进行了变异,则不会重新绘制

// simulating request there is not repaint
setInterval( () => {
  this.list[0].name = "Gustavo"; // no repaint because it's the same value
  this.list[1].name = "Costa 2"; // repaint
}, 2000);

您可以使用上面的plnkr链接对此进行测试。

这是因为您每次都在创建一个新的数组,并且由于参考已更改,角度正在更新。如果每2秒将其分配给同一个引用,则情况并非如此

otherList=[{name:'Gustavo'},{name:'costav'}];
构造函数(){
this.list=[{name:'Gustavo'},{name:'costav'}]
设置间隔(()=>{
this.list=this.otherList;
}, 2000);    
}

要添加到@0mpurdy中,
对象(以及
数组
)永远不相等,即使它们具有相同的属性和值,除非一个是另一个的引用,或者它们共享相同的引用


另一方面,原语可以与其他原语相同,因为它们是按值比较的,而不是按引用比较的。这就是为什么手动覆盖相同值的值时不会触发更改检测,但如果替换整个对象,即使对象明显相等,更改检测将被触发。

这是因为Angular使用默认的
trackByFunction
作为
DefaultIterableDiffer
按标识跟踪项目

consttrackbyidentity=(索引:编号,项:任意)=>item;
所以很明显,当你创建一个新的数组时,它会创建新的对象引用和角度变化。即使您没有更改数组引用,Angular仍会认为项目已更改,因为对象引用已更改:

setInterval(()=>{
this.list.length=0;
this.list.push({name:'Gustavo'});
this.list.push({name:'Costa'});
}, 2000);
您可以提供自定义
trackByFunction
以按对象名称进行跟踪:

@组件({
选择器:“我的应用程序”,
模板:`
{{item.name}
`
})
导出类应用程序{
清单:[];
识别(索引、项目){
返回item.name;
}
这样就不会更新DOM。请参阅


由于您对
ngFor
很感兴趣,您也可以阅读我在哪里解释
ngFor
如何在引擎盖下工作。

如果您将其指定为相同的参考,则不会有任何更改)当然,Angular不会更新DOM@Maximus我想这就是他要问的,不是吗?为什么如果阵列没有改变,角度也会改变ion-A:因为它是通过引用的?不,他在问为什么对数组引用进行udpating会触发DOM udpate,而对数组进行变异则会触发DOM udpatenot@Maximus很公平-但我所说的仍然没有回答他的问题,因为我解释了为什么它是通过引用-奥斯曼给出了一个更好的答案,你应该像我一样投票给他:)是的)读我的answ呃,这与默认
trackBy
函数的工作方式有关Hey Maximus,再次感谢你!对于AngularJS开发人员来说,$$hashKey是AngularJS中对象的引用?Angular的trackBy与AngularJS有着相同的想法?(同样的概念也适用于AngularJS这篇文章?)?@GustavoCosta,不客气。是的,我的想法是一样的AngularJS@Maximus如果返回1、false或nothing(所有项接收相同的trackBy:id),则标识方法异常重新粉刷不合适occur@GustavoCosta,因为您每次都返回相同的值是的,但在AngularJS中,您不能向所有元素返回相同的trackBy值,这是有意义的,因为AngularJS使用此值跟踪ng repeat中的模型和元素。
// simulating request there is not repaint
setInterval( () => {
  this.list[0].name = "Gustavo"; // no repaint because it's the same value
  this.list[1].name = "Costa 2"; // repaint
}, 2000);