Цикл обнаружения угловых изменений, запускаемый с помощью геттеров внутри шаблона

#angular #typescript #loops #angular6 #angular-changedetection

#angular #typescript #циклы #angular6 #angular-changedetection

Вопрос:

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

Справочная информация:

Я действительно считаю, что использование геттеров внутри шаблона — это самый чистый подход с точки зрения удобства обслуживания, однако, по-видимому, из-за того, что Angular не может знать, изменилось ли значение getter, пока не вызовет его, он просто вызывает его все время. Я пока нашел три альтернативы:

  1. Прекратите использование геттеров, сделайте все свойства общедоступными и получите к ним прямой доступ
  2. Сохраните значение каждого геттера в общедоступном свойстве компонента и привяжите его вместо геттера в шаблоне
  3. Измените режим обнаружения изменений в Angular с default на OnPush

Вариант 1 может показаться нелогичным по сравнению с преимуществами использования классов Typescript. Вариант 2 может показаться ненужным дублированием кода и снизить удобство сопровождения, вариант 3 потребует значительного рефакторинга.

Вот пример (упрощенный для иллюстративных целей)

Модель:

 export class UserModel { 
  private id: string;

get getId() {
    console.log('Getting id');
    return this.id; 
}
set setId(id) {
   this.id = id;
}
constructor() {
}
}
  

Component.html

 <h1>Test</h1>
<p>{{user.getId}}</p>
  

Component.ts

   import {Component, OnInit} from '@angular/core';
    import {TestModel} from './test.model';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent implements OnInit {
      public user: UserModel;
    
    ngOnDestroy() {
      if (this.userObserver) { this.userObserver.unsubscribe(); }
    }

    ngOnInit() {
      this.userObserver = this.userObservable.subscribe(
      (data: UserModel) => {
        this.user = data;
      },
      (err: any) => {
        console.error(err);
      });
    }
  }
  

Выведет следующий консольный журнал:
консоль.вывод журнала

Кто-нибудь может порекомендовать наилучшую практику, позволяющую избежать ненужных циклов при работе со сложными моделями в Angular? Или даже правильный способ отладки такого типа поведения, в том виде, в каком он есть сейчас, I am console.регистрирует методы получения и отслеживает всплески использования memmory.

РЕДАКТИРОВАТЬ (Ответ) После более продолжительного исследования, копания в трассировках стека, я обнаружил, что бесконечный цикл обнаружения изменений на самом деле был вызван внедренной нами службой под названием ‘Sentry’. По-видимому, это вызывает проблему при запуске консоли.используется журнал, который запускает обнаружение изменений. Нашел проблему github по этому поводу здесь:github.com/getsentry/sentry-javascript/issues/1883 Не нашел решения (кажется, по своей сути несовместимым), обновится, если я найду для этого исправление.

Комментарии:

1. Используете ли вы геттеры или нет, ничего не меняет: Angular по-прежнему необходимо обнаруживать изменения, и, следовательно, ему по-прежнему необходимо оценивать выражения. Использование геттера позволяет вам заметить, потому что вы можете добавить состояние ведения журнала, в то время как вы не замечаете его при использовании полей из-за отсутствия операторов ведения журнала. Но независимо от того, используете вы геттер или нет, произойдет одинаковое количество обнаружений изменений и вычислений выражений.

2. В качестве дополнительного примечания: получатель и установщик должны иметь одно и то же имя (название свойства). Например: get id() { return this._id; } set id(value) { this._id = value; } .

3. @JBNizet, спасибо за подтверждение этого, получилось довольно запутанно, поскольку в нескольких комментариях к переполнению стека упоминалось, что использование методов может вызвать это. После более продолжительного исследования, копаясь в трассировках стека, я обнаружил, что бесконечный цикл обнаружения изменений на самом деле был вызван внедренной нами службой под названием «Sentry». По-видимому, это вызывает проблему при запуске консоли. используется журнал, который запускает обнаружение изменений. Нашел проблему github по этому поводу здесь: github.com/getsentry/sentry-javascript/issues/1883 Не нашел решения (кажется, по своей сути несовместимым), обновится, если я найду для этого исправление.

4. @d_stack обнаружил это с помощью @sentry/browser@5.19.2 в Angular 8.2.7. не могли бы вы обновить фактический ответ тем, что, по вашему мнению, было лучшим решением цикла обнаружения изменений?

Ответ №1:

Использовать ChangeDetectionStrategy.onPush

Выполните следующую команду, чтобы установить это значение по умолчанию для вашего проекта при создании новых компонентов через CLI.

ng config schematics.@schematics/angular.component.changeDetection OnPush

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