Angular 1.x vs 2变化检测性能



我一直在玩AngularJS 1.x和Angular 2,试图比较它们的性能。

这是一个Plunkr,显示了Angular 1.x的"缺点"。如果作用域中存在太多元素,则在编辑输入字段时,您会注意到呈现输入字段的滞后,因为框架每次检测到可能更改任何元素的事件时,都会检查作用域中的所有元素。

摘录自第一个Plunkr(html):

<body ng-app="myApp">
<div ng-controller="myCtrl">
<input ng-model ="name"></input>
Hello, {{name}}!
<button ng-click="generateFields()">
Generate 5000 elements
</button>
{{list}}
</div>

摘自第一本Plunkr(js):

myApp.controller('myCtrl', function($scope) {
$scope.name = 'name';
$scope.list = [];
$scope.generateFields = function(){
for(i=0; i<5000;i++){
$scope.list.push(i);
}
}

});

在这个Plunkr中,我在Angular 2中写了一个类似的示例。看起来一点也不滞后。这在Angular 2中是如何解决的?框架是否知道只有输入字段发生了更改,或者由于VM优化的更改检测器,它只是更快地执行脏检查?

摘录自第二部Plunkr:

@Component({
selector: 'my-app',
providers: [],
template: `
<div>
<div>{{myProp}}</div>
<input [(ngModel)]="myProp" />
<button (click)="generateFields()">Generate</button>
<div>{{myList}}</div>
</div>
`,
directives: []
})
export class App {
constructor() {
}
myProp :string = "Change me!";
myList :any = [];
generateFields(){
for (var i = 1; i < 5000; i++)
{       
this.myList.push(i);
}
console.log("fields generated");
}
}

没错。Angular2CD非常高效,因为它如何使用区域以及在绑定和事件中拆分双向绑定。您可以使用ChangeDetectionStrategy进行进一步优化。OnPush

因为更改检测在prodmode中只运行一次?我没有尝试过,因为无论列表中添加了多少元素,我都没有注意到angular 2示例中有任何滞后。

我不知道Angular 1.x,所以我不知道它为什么慢。Angular2仅在触发订阅事件或完成异步调用时运行更改检测。Angular也不比较对象或数组的内容,它只进行===检查。

如果angular只进行===检查,那么在您单击第二个plunkr中的Generate按钮后,它如何知道需要将更改传播到DOM?元素被添加到数组中,但数组对象的引用不会更改。

我认为这是因为<div>{{myList}}</div>绑定到myList.toString(),并且在每个更改检测周期(例如单击按钮后),它会比较包含不同值时不同的结果。例如,如果您改为<child-comp [data]="myList">,那么当ChildComponent未绑定到{{myList}}时,将不会发生任何事情。

由于VM优化的更改检测器,执行脏检查是否更快?

很难说,因为Angular 2中的变化检测与Angular 1完全不同。我认为唯一相同的是脏检查模板绑定的(逻辑)概念。最有可能的是Angular 2在为每个组件创建的更改检测器对象中生成的单形态(VM友好/优化)代码——Angular博客、thoughtram博客、V.Savkin talk。

请看第二个plunkr,我刚刚更新了它。现在它有一个子组件,它将列表作为输入参数。我一介绍这一点,Angular就被迫对阵列进行深入检查,因为默认的CD策略,这意味着一旦生成足够的元素,性能就会显著降低。尽管如此,它仍然比角1快得多。最重要的是,在默认CD策略的情况下,会深入检查输入参数的变化,但组件的"本地"变量不会。

由于Property绑定是另一个绑定表达式,因此Angular默认情况下会进行深度检查。

如果模板绑定包含可迭代的内容(例如[myList]="myList"),则仅在开发模式下,即使没有NgFor循环或其他创建到子组件中每个元素的模板绑定的东西,更改检测实际上也会遍历所有(如myList)项并进行比较。这与在生产模式中执行的looseIdentical()检查(即===检查,因此为参考检查)非常不同。正如您所发现的,对于非常大的迭代,这可能会对性能产生影响,仅在开发模式下。

请参阅https://stackoverflow.com/a/37356950/215945为了对此进行更深入的讨论;devMode only deep checking";。

最新更新