Fjut
Fjut

Reputation: 1324

Angular 1.x vs 2 Change detection performance

i 've been playing around with AngularJS 1.x and Angular 2, trying to compare their performance.

Here is a Plunkr showing a 'down-side' with Angular 1.x. If too many elements are present on the scope, you will notice lags in rendering the input field as you edit it, since the framework will check all elements on the scope each time it detects an event that could have changed any.

Excerpt from the first 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>

Excerpt from the first 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);
  }
}

});

In this Plunkr, i 've written a similar sample in Angular 2. It seems that there is no lag at all. How is this resolved in Angular 2? Does the framework somehow knows that only the input field is changed, or is it just faster in performing dirty checking because of the VM optimized change detectors?

Excerpt from the second 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");
  }
}

Upvotes: 3

Views: 868

Answers (2)

Mark Rajcok
Mark Rajcok

Reputation: 364677

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

It is hard to say, since change detection in Angular 2 is completely different from Angular 1. I think the only thing that is the same is the (logical) concept of dirty checking template bindings. Most likely it is the monomorphic (VM-friendly/optimized) code – Angular blog, thoughtram blog, V.Savkin talk – that Angular 2 generates in the change detector objects that it creates for each component.

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.

If a template binding contains something that is iterable – e.g., [myList]="myList" – then in development mode only, change detection actually iterates through all of the (e.g. myList) items and compares them, even if there isn't an NgFor loop or something else that creates a template binding to each element in the child component. This very different from the looseIdentical() check (i.e., === check, hence reference check) that is performed in production mode. For very large iterables, this could have a performance impact, in development mode only, as you discovered.

Please see https://stackoverflow.com/a/37356950/215945 for a more in-depth discussion related to this "devMode only deep checking".

Upvotes: 1

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 657238

Exactly. Angular2 CD is extremely efficient because how it uses zones and the split of two-way-binding in bindings and events. You can further optimize using 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.

I don't know Angular 1.x, therefore I can't tell why it is slower. Angular2 only runs change detection when a subscribed event was fired or an async call was completed. Angular also doesn't compare contents of objects or array, it does only === checks.

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.

I think it's because <div>{{myList}}</div> binds to myList.toString() and at every change detection cycle (for example after button click) it compares the result which is different when it contains different values. If you for example did instead <child-comp [data]="myList">, nothing would happen when ChildComponent doesn't bind to {{myList}}.

Upvotes: 4

Related Questions