4

I would like to ask about *ngIf binding to function return value. Will it have performance overhead when comparing *ngIf binding to property.

This is only sample code for asking concept, the data structure is complex than that in DataService. The enable flag will be saved in a map object. This is just a simple expression:

In typescript service

export class DataService() {
   private enable: boolean;

   isEnable() {
      return enable;
   }

   getEnableValue() {
      return enable;
   }

   update(flag: boolean) {
      enable = flag;
   }
}

In html,

<div *ngIf="isEnable()">
    <p> {{ testObject.value }}</p>
</div>

In typescript,

isEnable() {
   return this.dataService.isEnable();
}

vs

In html,

<div *ngIf="isEnable">
    <p> {{ testObject.value }}</p>
</div>

In typescript,

isEnable: boolean;
ngOnInit() {
    isEnable = this.dataService.getEnableValue()
}

For *ngIf="isEnable", I am able to understand。 But for function binding,is angular check the property in the function and monitor it changes? Any performance difference?

Thanks a lot.

ConnorsFan
  • 70,558
  • 13
  • 122
  • 146
rodent_la
  • 1,195
  • 4
  • 18
  • 38
  • Add `console.log("hello")` to your function, and you'll know. It's called at each change detection, to know if the element should be added or removed from the DOM. – JB Nizet Aug 03 '18 at 13:53
  • It will have performance difference depending on the complexity of your function. If you just have a property binding, then it is just checking that property.If you have a function that loops through, say, 3,000 items in an array, then that loop will run every single time a change detection is triggered. So yes, performance wise, a property variable is better. – David Anthony Acosta Aug 03 '18 at 13:58
  • I know *ngIf is to add or remove from the DOM. May be my question is not clear. I would like to ask is that the value changes in function and the value changes in property that assign to *ngIf, does it impact on performance for 2 different style writing? – rodent_la Aug 03 '18 at 13:58
  • It depends on what `this.dataService.isEnable()` has to do before returning the value. – ConnorsFan Aug 03 '18 at 14:23
  • 1
    Angular will have to reevaluate the function to know if it has changed. I would use a Subject or BehaviourSubject to avoid that. – fredrik Aug 03 '18 at 15:18
  • If the isEnable() in DataService has to access the map and retrieve its value: const object = map.get('type1'); return object.enable. Will every map content changes trigger evaluate function? – rodent_la Aug 03 '18 at 15:59
  • I think that every time it evaluates if the ui should be redrawn will trigger a revaluation of the function. Try to add a console.log to the getter and see how often it's called... or use a profiler. – fredrik Aug 03 '18 at 16:36
  • Thanks a lot. I got it. – rodent_la Aug 07 '18 at 03:39
  • Angular will always reevaluate the function on each application tick to ensure that the function outcome hasn't changed since last tick! Don't bind functions within an template! That's the worst you can do! Check out gunters answer: https://stackoverflow.com/questions/49320756/how-angular-change-detection-is-triggered-when-you-are-binding-to-a-function – Nightking Oct 29 '18 at 20:18

1 Answers1

3

Technically speaking there is no noticeable difference in performance.

When Angular compiles AOT templates they are converted into JavaScript source code, and all those one-way bindings are turned into functions.

So I there shouldn't be any noticeable performance when doing any of the following.

export class MyComponent {
     public title1: string;

     public get title2(): stirng {
          return this.title1;
     }

     public getTitle3(): string {
          return this.title1;
     }
}

Use all 3 above would have about the same performance.

Downsides

There are side effects to using functions.

  • it breaks the dry principle of a template
  • you can not see how complex a template is
  • performance is hidden inside functions

I've also found that you tend to do more work in the template. When you call functions it makes it easier to use *ngIf, *ngFor and other logical components.

When you read the source code for the component you don't get the full picture. There is a lot of the business logic being done in the template, and when you read the template you don't see how it will be viewed, because there is a lot logic in the template.

Reactgular
  • 52,335
  • 19
  • 158
  • 208
  • If the isEnable() in DataService has to access the map and retrieve its value: const object = map.get('type1'); return object.enable. Will every map content changes trigger evaluate function? – rodent_la Aug 03 '18 at 15:36
  • @rodent_la You're confusing performance and change detection. The two are different topics. If you are using OnPush (which you should be) then any changes in the services will not trigger template rendering, because you should be pushing data to the templates. – Reactgular Aug 03 '18 at 16:21
  • Thank you so much. – rodent_la Aug 07 '18 at 03:38
  • 3
    Indeed there is a performance impact! When you use a function instead of a immutable or primitive data type (boolean, string, number) angular has to evaluate the function each application tick / change tracking tick! That's the worst you can do! Use observables (rxjs) or pre-evaluate the state and persist it within a public accessible property to bind on the template! Reference: https://stackoverflow.com/questions/49320756/how-angular-change-detection-is-triggered-when-you-are-binding-to-a-function – Nightking Oct 29 '18 at 20:17