Может ли вызов простых методов в шаблонах угловых компонентов вызвать проблемы с производительностью? - PullRequest
3 голосов
/ 15 октября 2019

При чтении нескольких ресурсов Angular (см. Ниже) вызов методов в шаблонах может вызвать проблемы с производительностью. Например,

<div>{{getDisplayName()}}</div>

Однако довольно многие примеры библиотек угловых материалов вызывают методы в шаблонах.

Tree

https://material.angular.io/components/tree/examples

<mat-icon class="mat-icon-rtl-mirror">
    {{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
</mat-icon>

Таблица с выбором

https://material.angular.io/components/table/examples

<td mat-cell *matCellDef="let row">
  <mat-checkbox (click)="$event.stopPropagation()"
                (change)="$event ? selection.toggle(row) : null"
                [checked]="selection.isSelected(row)"
                [aria-label]="checkboxLabel(row)">
  </mat-checkbox>
</td>

Эти методы возвращают значение из набора. Например, https://github.com/angular/components/blob/4d4ee182de3f306c5fcf49853ef6ac71c4000eea/src/cdk/collections/selection.ts

isSelected(value: T): boolean {
   return this._selection.has(value);
}

Будут ли эти методы вызывать проблемы с производительностью, как * нормальные методы? Или мне чего-то не хватает?

Ресурсы

Вызывает ли вызов функций в шаблонах проблемы с производительностью в Angular2 +?

https://blog.mgechev.com/2017/11/11/faster-angular-applications-onpush-change-detection-immutable-part-1/

1 Ответ

0 голосов
/ 15 октября 2019

Окончательный ответ на вопрос: да - это приведет к проблемам с производительностью. И, к счастью, на самом деле легко показать, почему и как вы можете их преодолеть.

В целях иллюстрации я хочу, чтобы вы скопировали ряд этих флажков и вставили их в свое приложение.

Затем в методе checkboxLabel я хочу, чтобы вы поместили журнал консоли в самую первую строку. Выполните любое взаимодействие со страницей, в идеале установите и снимите один из флажков.

Теперь, если вы проверите свою консоль, вы можете ожидать увидеть журнал консоли checkboxLabel, появившийся один раз для каждого mat-checkbox. Так что, если вы вставите три, вы ожидаете увидеть это, 3 раз.

Но если вы точно следовали этим инструкциям, вы на самом деле увидите журнал консоли, много раз, в зависимости от того, что именно вы сохранили на своей тестовой странице и настройки вашего проекта. И под многими мы имеем в виду, конечно, 9 + раз .

Как это случилось?

По сути, ядро ​​того, как работает Angular, каждый раз, когда происходит изменение в DOM, каждый элемент с таким методом долженбыть переоценены. По сути, он не кэширует предыдущее значение и не сравнивает их, поэтому он должен снова выполнить вычисление и вернуть результат.

Итак, если у вас было 20 делений с displayName (), это много изменений КАЖДЫЙ раз, когда есть изменения. Что по понятным причинам вызывает огромную проблему с производительностью. Когда вы думаете, что на большинстве страниц отображается гораздо больше, чем это отображается, вы можете увидеть, как люди изо всех сил пытаются поддерживать производительность своих приложений не потому, что они плохо умеют кодировать, а потому, что они не могут точно понять, что заставляет их отставать от сцены.

Как вы можете это преодолеть?

Трубы.

Если вместо этого мы преобразуем наш метод в канал, который все еще может использовать этот метод, мы МОЖЕМ воспользоваться этим методом кэширования и сделать наше приложение в целом быстродействующим.

Каналы ТОЛЬКО возвратят другойрезультат, и будет вызывать только их функцию, ЕСЛИ ввод изменяется.

Итак, для простоты: давайте создадим фиктивный файл ts, который имеет следующий массив.

labelExamples = [
    { row: '1' },
    { row: '1' },
    { row: '3' }
]

И html-файл, имеющий следующий код:

<ng-container *ngFor="let l of labelExamples">
    <div>{{checkboxLabel(l.row)}}</div>
</ng-container>

И, наконец, давайте вернемся к нашему файлу ts и скажем, что наша функция checkboxLabel выглядит следующим образом:

  checkboxLabel(row: string) {
    switch (row) {
      case '1':
        console.log("hello");
        return 'Row 1 Label';
      default:
        console.warn("hello from the other side");
        return 'Any other row label'
    }
  }

(Вы можете использовать это, чтобы протестировать в точности то, что я описал выше).

Что ж, если вы запустите это, вы увидите точно так же, как я описал, многие экземпляры консольного журнала«Привет» и «Привет с другой стороны».

Но, если мы изменим это на канал, мы могли бы преобразовать вышеприведенное в следующее

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'checkboxLabelPipe'
})
export class checkboxLabelPipe implements PipeTransform {
  transform(row: string | string): string {
    if (row) {
      return this.checkboxLabel(row);
    }
    return row;
  }

  checkboxLabel(row: string): string {
    switch(row) {
      case '1': 
        console.log('Row 1 called');
      return 'Row 1 Label';
      default: 
        console.log('Any other row called');
      return 'Any other row label'
    }
  }
}

Помните, что это канал,и поэтому он должен быть объявлен в NgModule, в котором он используется, или в глобальном NgModule.

Если вы запустите это вместо того, чтобы сохранить тот же HTML-файл и тот же массив labelExamples, вы увидите тот же результат, что и раньше, за исключением того, что если вы посмотрите в журналы консоли, вы увидите ближек тому, что вы изначально ожидаете. 3 консольных бревна.

Точно понимая, когда и как выполняются вычисления в Angular, и когда лучше всего использовать функции или каналы, вы можете значительно повысить производительность всего приложения.

Подробнее о том, как Пайпс добивается этого, вы можете прочитать в угловой документации. Документация по угловым трубам

Кроме того, для еще большего повышения производительности вы можете заглянуть в мемо-декоратор. Здесь можно найти мемо-декоратор npm. , который кэширует уже рассчитанные результаты и сохраняет вам еще большую производительность, возвращая сохраненные результаты, а не подвергая их процессу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...