Angular performance: ngStyle recalculates on each click on random input

前端 未结 2 1248
醉酒成梦
醉酒成梦 2021-01-06 10:53

I have a very stupid performance issue.

I have a component that uses ngStyle, and I\'d prefer to not rewrite it. But each time I click

2条回答
  •  萌比男神i
    2021-01-06 11:14

    That makes perfect sense. This is how Angular performs change detection. And this is Angular performing extra checks since you called a function in one of the data-binding syntaxes, here:

    [ngStyle]="{'background-color': getBG(row*col)}" 
    

    Angular performs Change Detection in three cases:

    1. DOM Events.
    2. AJAX Calls.
    3. Timeouts / Intervals.

    This is the case of DOM Events (click).

    Now when performing Change Detection, Angular check whether a particular variable in the Component has changed.

    That's pretty straight forward in case of properties. But not so straight-forward in case of functions.

    You see, the only way to determine whether the value of a function has changed is by calling it.

    So Angular is doing just that.

    SOLUTION:

    Just create a matrix for the number to show and the color to paint right in the Component Class:

    import { Component } from '@angular/core';
    
    @Component({
      selector: 'my-app',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
      rows = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
      cols = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
      matrix = [];
    
      model1 = '';
      model2 = '';
      model3 = '';
      model4 = '';
      model5 = '';
    
      ngOnInit() {
        this.rows.forEach((row, rowIndex) => {
          this.matrix.push([]);
          this.cols.forEach((col, colIndex) => {
            const product = row * col;
            this.matrix[row].push({
              numberToShow: product,
              color: this.getBG(product),
            });
          })
        });
      }
    
      getBG(hue: number): string {
        console.log('getBG was called');
        return 'hsl(' + hue + ', 100%, 50%)';
      }
    
    }
    

    And then use it in your template:


    1. Open a console

    {{col.numberToShow}}

    2. Click fast on the different inputs:

    Difference in the performance:

    In the previous implementation, the getBG was called 401 times on initialization.

    In the solution implementation, the getBG is called 101 times on initialization.

    That's a massive performance gain of around 397%.

    Plus there's no extra call to the getBG method when the user focuses and blurs out from any input field.

    Here's a Working Sample StackBlitz for your ref.

    You might also want to read through a Medium Article that I wrote about Performant Reactive Forms in Angular. Although it's related to Reactive Forms, I've touched upon this aspect, in the article. I'm sure you'll find it helpful.

提交回复
热议问题