12

似乎在模板中使用 getter 会导致 Angular 更改检测进入循环(getter 被调用数百次)。在阅读了大量关于类似问题的文章后,我似乎无法得到明确的答案。

背景资料:

从可维护性的角度来看,我确实相信在模板中使用 getter 是最干净的方法,但似乎因为 Angular 在调用它之前无法知道 getter 值是否发生了变化,它只是一直调用它。到目前为止,我找到了三种选择:

  1. 停止使用 getter,公开所有属性并直接访问它们
  2. 将每个 getter 的值存储到组件上的公共属性中并绑定它而不是模板中的 getter
  3. 将 Angular 的 changeDetection 模式从默认更改为 onPush

对于使用 Typescript 类的好处,选项 1 似乎违反直觉。选项 2 似乎是不必要的代码重复并降低了可维护性,选项 3 需要进行重大重构。

这是一个示例(为说明目的而简化)

模型:

export class UserModel { 
  private id: string;

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

组件.html

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

组件.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);
      });
    }
  }

将输出以下控制台日志: console.log output

任何人都可以推荐最佳实践来避免在 Angular 中处理复杂模型时出现不必要的循环吗?甚至是调试此类行为的正确方法,就目前而言,我是控制台。记录 getter 方法并观察内存使用峰值。

编辑(答案) 经过更多时间调查,挖掘堆栈跟踪后,我发现无限变化检测循环实际上是由我们注入的名为“Sentry”的服务引起的。显然,当使用触发更改检测的 console.log 时,它会导致问题。在这里找到了一个关于它的 github 问题:github.com/getsentry/sentry-javascript/issues/1883没有找到解决方案(似乎天生不兼容),如果我找到解决方案,将更新。

4

1 回答 1

1

利用ChangeDetectionStrategy.onPush

通过 CLI 创建新组件时,运行以下命令将其设为项目的默认设置。

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

一般来说,尽量避免在模板中使用复杂的 getter 或调用函数。如果您需要转换数据,请考虑使用已记忆的Pipes

于 2021-07-10T00:39:38.347 回答