3

我一直在玩 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");
  }
}
4

2 回答 2

4

确切地。Angular2 CD 非常高效,因为它在绑定和事件中如何使用区域以及双向绑定的拆分。您可以使用 ChangeDetectionStrategy.OnPush 进一步优化

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

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

如果是这种情况,Angular 只进行 === 检查,那么在您单击第二个 plunkr 中的“生成”按钮后,它如何知道需要将更改传播到 DOM?元素被添加到数组中,但数组对象的引用没有改变。

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

于 2016-06-06T17:18:58.063 回答
1

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

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

请看一下第二个 plunkr,我刚刚更新了它。现在它有一个子组件,它将列表作为输入参数。我一介绍,由于默认的 CD 策略,Angular 被迫对数组进行深度检查,这意味着一旦生成足够的元素,性能就会显着降低。不过,它仍然比 angular 1 快得多。底线是,在默认 CD 策略的情况下,深入检查输入参数的变化,但组件“本地”变量没有。

...并且由于属性绑定是另一个绑定表达式,它使 Angular 默认进行深度检查。

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

请参阅https://stackoverflow.com/a/37356950/215945以获得与此“仅 devMode 深度检查”相关的更深入讨论。

于 2016-06-07T14:56:15.020 回答