代码之家  ›  专栏  ›  技术社区  ›  Raul Rene

即使没有做任何更改,角度也可以无限地重新渲染,这正常吗?

  •  3
  • Raul Rene  · 技术社区  · 6 年前

    问题

    角度设计是为了不断地重新检查所有的东西以检测变化吗?我来自反应世界 event triggered -> re-rendering 是的。我不知道这是来自我的应用程序还是来自角度。

    如果我有一个从html模板调用的方法,即使组件中的任何内容都没有改变,它也会被无限地调用。

    问题

    我有一个类似日历的页面,它加载了很多数据,并且在呈现之前必须计算一些东西,因为使用 ngIf 指令。所以我的模板中有如下内容:

    <div [innerHTML]="_getDayPrice(item, day) | safeHtml"></div>  
    

    如果我在控制台上 _getDayPrice 方法, 它被无限地打印出来 是的。

    我试过的

    1. 我通过人工注射 ChangeDetectionRef 在我的应用程序中 this.cdRef.detach() 是的。不过,这感觉很烦人,因为有时我可能需要重新启用它并再次分离。

    2. 我试着调查它是否来自我的父组件应用,比如容器。我已经在主app.component中呈现了一个类似div的 <div class={{computeClass()}}> 在这个方法中,打印了一个控制台日志,并确定它被无限地调用。所以在这之后,我试着评论掉所有应用程序的服务。如果所有的数据都被注释掉了,那么它确实可以正常工作,但是也没有可观察到的数据。我调查了大约半天,找不到一点故障(比如评论这项服务修复了一切)。

    3. 使用Chrome内置的性能选项卡记录性能,但再也找不到任何触发更改的代码。 zone.js 多次调用,并似乎设置了一个持续触发的间隔。

    4. 我当然在找 setTimeout setInterval 在服务中,但找不到可能导致此问题的不断更改的内容。

    结论?

    底线是:如果你有一个复杂的角度应用程序并从模板中调用一个方法,那么这个方法被无限调用,这正常吗?

    如果不是的话,你有什么线索可以说明这是什么原因吗?或者其他方法绕过它而不是分离changeref检测器?

    我唯一关心的是表现。这是一个类似日历的页面,可以呈现多行,而且在8GB的RAM笔记本电脑上会严重滞后。我敢肯定平板电脑或手机几乎会冻僵。

    2 回复  |  直到 6 年前
        1
  •  4
  •   JusuVh    6 年前

    在转换html中的数据时,应尽可能频繁地使用管道。

    仅当管道对象或参数更改时才重新计算管道(因此,如果其中一个输入是对象,请确保创建该对象的新实例以触发重新计算)。对于大多数用途,可以使用管道而不是函数。

    import { Pipe, PipeTransform } from '@angular/core';
    
    @Pipe({
      name: 'getDayPrice'
    })
    export class GetDayPricePipe implements PipeTransform {
    
      transform(item: string, day: string): string {
        // ... do whatever logic here
        return item + day;
      }
    
    }
    

    然后像这样使用它:

    <div [innerHTML]="item | getDayPrice:day | safeHtml"></div>
    
        2
  •  4
  •   Pierre Mallet    6 年前

    有两种机制可用于减少绑定检查的数量

    1个- ChangeDetectorRef.detach :允许将组件从更改检测循环中分离出来,因此在重新连接之前不会刷新出价。

    2个- ChangeDetectionStategy.OnPush :tell angular仅当至少有一个组件@input发生更改时,才需要检查组件的绑定。你可以帮我找到如何使用它的细节 here

    在imo中,您应该创建一个包含item/days输入的组件来包装显示dom元素。有点像

    // wrap.component.ts
    @Component({
      template: '<div [innerHTML]="_getDayPrice() | safeHtml"></div>',
      changeDetection: ChangeDetectionStrategy.OnPush,
      ...
    })
    export class WrapComponent {
      @Input() item: Item;
      @Input() day: String; 
    
      private _getDayPrice = () => {
          // compute your HTML with this.item and this.day instead of parameters
          ....
      }
    }
    

    然后您应该看到只有当项目或日期更改时才会触发的逻辑。