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

Angular 1.x vs 2 Change detection performance

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

这里是 Plunkr 显示 'down-side' 和 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,我在Angular2写过类似的sample,貌似完全没有卡顿。 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");
  }
}

没错。 Angular2 CD 非常有效,因为它如何使用区域以及绑定和事件中双向绑定的拆分。您可以使用 ChangeDetectionStrategy.OnPush

进一步优化

Because the change detection will run only once in prodmode? I haven't tried it because I haven't noticed any lags in the angular 2 example, no matter how many elements are added to the list.

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

If this is the case that angular does only === checks, how does it know that it needs to propagate the change to DOM after you've clicked on the Generate button in the second plunkr? Elements are added to the array but the reference of the array object is not changed.

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

时,什么也不会发生

Is it just faster in performing dirty checking because of the VM optimized change detectors?

很难说,因为 Angular 2 中的变化检测与 Angular 1 完全不同。我认为唯一相同的是脏检查的(逻辑)概念模板绑定。很可能是单态 (VM-friendly/optimized) 代码 – Angular blog, thoughtram blog, V.Savkin talk – Angular 2 在它为每个组件创建的变化检测器对象中生成。

Please have a look at the second plunkr, i just updated it. Now it has a child component which gets the list as an input parameter. As soon as I introduced that, Angular was forced to do a deep check of the array because of the default CD strategy, meaning that performance lowered significantly as soon as you generate enough elements. It is still significanlty faster than angular 1 though. Bottom line, input parameters are deeply checked for changes in case of a default CD strategy but component 'local' variables are not.

... and since Property binding is another binding expression, it makes Angular to do deep checking by default.

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

请参阅 以了解与此“仅 devMode 深度检查”相关的更深入讨论。