7

我们的 Angular 应用程序中有许多组件需要每秒定期显示每个组件独有的新值(倒计时、时间戳、经过的时间等)。最自然的方法是创建使用 RxJStimerinterval工厂函数的 observables。但是,这些会在整个应用程序的每个间隔触发 Angular 更改检测,次数与调用间隔函数的次数一样多。如果页面上有几十个组件,这会触发整个应用程序每秒或时间段数十次的更改检测,从而产生很大的性能开销。

到目前为止,我尝试了两种方法来解决这个问题。任何一个的好答案都会非常有帮助 - 理想情况下两者都是。我想避免手动触发更改检测,而是依赖从 Observables 发出的新值,并让异步管道/OnPush 更改检测策略负责触发更改检测。如果这不可能,我想了解原因。

  1. 有什么方法可以禁用或阻止 RxJStimerinterval函数触发 Angular 更改检测?使用 NgZonezone.runOutsideAngular(() => this.interval$ = interval(1000) ... )似乎不会这样做。StackBlitz 示例:https ://stackblitz.com/edit/angular-zo5h39
  2. 或者,如果我使用 RxJSSubject结合setInterval调用 inside创建一个 Observable 流zone.runOutsideAngular,为什么当从主题发出新值时不会为子组件触发更改检测?StackBlitz 示例:https ://stackblitz.com/edit/angular-yxdjgd
4

1 回答 1

9
  1. 有什么方法可以禁用或阻止 RxJS 计时器或间隔函数触发 Angular 变化检测?使用 NgZone zone.runOutsideAngular(() => this.interval$ = interval(1000) ... ) 似乎不会这样做。

这是因为 observables 是冷的,并且值生产者 (setInterval) 仅在订阅发生时执行。在这里阅读更多。尽管此代码在 Angular 区域之外执行:

() => this.interval$ = interval(1000) ...

它实际上并没有立即调用interval操作符内部的值生产者。稍后将在IntervalInnerComponent订阅中的 AsyncPipe 时调用它。这发生在 Angular 区域内部:

在此处输入图像描述

在下一个替代方案中使用主题,您可以使其变得热门并立即在 Angular 区域之外订阅。

  1. 或者,如果我使用 RxJS Subject 结合 setInterval 创建一个 Observable 流,在 zone.runOutsideAngular 中调用... setInterval 值正在创建(可以手动订阅),但异步管道似乎没有触发更改检测

因为 Async Pipe 不会触发变更检测。它只是标记一个组件及其所有祖先,以便在接下来的更改检测期间随时检查。有关更多详细信息,请参阅此答案本文。Zone.js 触发变更检测。但由于您在setIntervalAngular 区域之外运行,它不会触发它。在此设置下,您有几个选项:

  • 注入ChangeDetectorRef并手动触发组件及其祖先的更改检测
  • 注入ApplicationRef并手动触发整个应用程序的更改检测
于 2018-12-04T18:37:48.357 回答