Angular 7:从订阅内部调用 ChangeDetectorRef detectChanges() 会导致无限循环

Posted

技术标签:

【中文标题】Angular 7:从订阅内部调用 ChangeDetectorRef detectChanges() 会导致无限循环【英文标题】:Angular 7: ChangeDetectorRef detectChanges() causes infinite loop when called from inside a subscription 【发布时间】:2019-04-27 07:06:46 【问题描述】:

我在阅读了与变更检测和类似帖子相关的所有材料并且未能解决我的问题后发布在这里。

ChangeDetectorRef detectChanges() 从订阅内部调用时会导致无限循环。如果我不打电话给detectChanges,我会收到ExpressionChangedAfterCheck 错误。我真的不知道如何解决,为什么ExpressionChangedAfterCheck错误来了

ngAfterViewInit() 
    this.route.params.subscribe((params) => 
      this.userId = params.userId;
      if (this.userId != undefined) 
        this.loadActivity();
      
      else 
        alert("Userid not supplied");
      
      this.cdRef.detectChanges();
    );
  

  loadActivity() 
    while(this.layers.length > 0)
      this.layers.pop();
    
    this.loading = true;
    this.userService.authenticatedGet(ApiUrls.GetLocation(this.userId, this.activity.from.getTime(), this.activity.to.getTime()), ).subscribe(
      (res:any) => 
        this.user = res.user;
        this.loading = false;
        // other logic
        this.cdRef.detectChanges();
        console.log("Loading is " + this.loading);
      
    );
  

注意:只有在值与ngIf绑定时才会出现此问题。

【问题讨论】:

如果您删除this.cdRef.detectChanges(); 之一,您会收到ExpressionChangedAfterCheck 错误吗? @ArtyomAmiryan 是的,亲爱的,即使我将调用包含在 setTimeOut 中,我也会收到这个令人沮丧的错误。我人生中第一次想到 Angular 的替代方案。在每个新版本之后,我们都会有新的怪癖。 首先在循环中订阅是错误的,在您的while 循环中想象您订阅Observable 的次数,每次迭代更新属性值的目的是什么@ 987654331@ 和 loading 内订阅? 再看一次,它是一个用于清除旧数据的while循环 试试markForCheck 而不是detectChanges 【参考方案1】:

我解决了这个问题。问题不在于生命周期,而是来自 ngx-leaflet 项目的指令 leaflet

当我删除传单相关指令和绑定时,所有错误都消失了。

错误也随之而来:

<ng-container *ngIf="!loading">
    <div
      class="map"
      leaflet
      (leafletMapReady)="onMapReady($event)"
      [leafletOptions]="options"
      [leafletLayers]="layers"
      [leafletLayersControl]="layersControl">
    </div>
</ng-container>

我尝试交替添加 detectChanges 和 markForCheck,但还是没有成功。

  onMapReady(map: Map) 
    this.map = map;
    setTimeout(() => map.invalidateSize(), 1000);
    this.route.params.subscribe(params => 
      this.userId = params["userId"];
      this.loadActivity();
    );
    this.cdRef.markForCheck();
  

最后,我在写这个答案时放弃了传单,我打算试试 Angular-Google-Maps。

是的,A-G-M 工作正常。

【讨论】:

以上是关于Angular 7:从订阅内部调用 ChangeDetectorRef detectChanges() 会导致无限循环的主要内容,如果未能解决你的问题,请参考以下文章

Angular 2:从订阅 http.post 获得响应后如何调用函数

Google Maps 的“map_changed”监听器内部调用的函数被多次调用

Angular 7 RxJs - HTTP 调用未在 ForkJoin 中完成

Angular 6 - 无法订阅从服务返回的数据

Angular 7 错误拦截器 – 原始调用有问题

如果已经使用相同的请求运行,则取消订阅/取消 Angular 4 中的现有 HTTP/XHR 调用