角度变化检测不仅仅检测产品中的变化

问题描述 投票:0回答:2

我遇到了一个奇怪的问题,我希望这对我来说只是一个简单的修复。 Angular 中的变更检测不仅仅在生产中起作用。

我使用 Angular 7 和 ngrx 作为状态管理构建了一个相当复杂的应用程序。有 2 个主要模块是基于路由进行延迟加载的。更改检测策略是 OnPush,99% 的应用程序遵循以下模式:数据通过 ngrx 效果从服务器发送到有状态组件,然后通过异步管道将数据推送到“虚拟”表示组件中。 示例:

this.loading$ = this.store.pipe(
  select(selector.isLoading),
  takeUntil(this.unsubscribe$)
);
<app-loading [loading]="loading$ | async"></app-loading>

ng serve
ng serve --prod
上一切都按预期进行,没有任何问题。然而,在运行
ng build --prod
并将 js 文件推送到我们的 .net 解决方案中后,更改检测将停止工作。

“停止工作”是什么意思?我的意思是,除非发生 DOM 事件,否则它不会更改任何模型或组件。

例如,使用上面显示的代码,会显示一个加载旋转器,直到数据来自服务器为止。在生产中,旋转器位于屏幕上,直到您随机单击。然后应用程序刷新并显示数据。这个问题在整个应用程序中持续存在。也就是说,这个问题不仅仅发生在那里。

应用程序加载到 .Net 解决方案中的 .cshtml 文件中,如下所示:

<script type="text/javascript" src="runtime.js"></script>
<script type="text/javascript" src="polyfills.js"></script>
<script type="text/javascript" src="main.js"></script>

延迟加载的模块位于 .cshtml 文件的文件夹内,并且没有显示任何错误,因此我必须假设所有内容都已正确连接。

同样,这仅在产品包中。不在开发或服务或生产模式服务。

angular deployment angular7 angular-cli-v7
2个回答
1
投票

这最终导致了来自操作员的 rxjs 的一个非常奇怪的情况。

应用程序使用signalR作为客户端和服务器之间的API。与集线器的大部分交互都是 jquery 承诺。我使用 from 运算符返回数据。

return from(this.proxy.invoke(...args));

由于我无法弄清楚的原因,这在开发中很有效。但观察者不会在生产中完成,因此即使状态会更新,视图仍在等待观察者完成。

我更新了代码以在连接上返回可观察值。

private async performInvoke(...argu): Promise {
  return await this.proxy.invoke(...argu);
}

invoke(...argu): Observable<any> {
  return new Observable(o =>
    const pInvoke = async () => {
      o.next(await this.performInvoke(...argu));
      o.complete();
    }
}

我在这里进行了简化,因此如果您发现这一点,请确保添加尝试捕获和其他错误保护。


0
投票

对于那些因不可靠的 ChangeDetection 面临类似问题的人:

我遇到过类似的问题,这只发生在定制的嵌入式 Chromium 中。

ChangeDetection 在本地主机环境中始终正常工作,但在通过 VNC 访问的嵌入式 Chromium 中并不可靠。即使二进制文件完全相同,应用程序的行为也不同,因此它一定是由浏览器中的某些内容引起的。

hacky 解决方案是通过

setInterval
强制进行更改检测,如下所示:

// AppComponent
private cdInterval = undefined;

ngOnInit() {
 this.cdInterval = setInterval(() => {
  this.cd.detectChanges();
}, 50);

ngOnDestroy() {
 if (this.cdInterval) {
  clearInterval(this.cdInterval);
 }
}

这显然远非理想,但至少 UI 保持同步。

郑重声明: 我已经尝试了所有我能想到的:

  • 异步管道
  • 观察值
  • 信号
  • 对每个变量更改强制使用 cd.detectChanges()

为每个订阅调用

cd.detectChanges()
可以,但无法扩展,所以我选择间隔调用它。

我会非常高兴有更好的解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.