在Angular中渲染基于时间的Observable,而不会出现压倒性的变化检测

Cra*_*ham 6 javascript rxjs angular angular-changedetection

我们的Angular应用程序中有许多组件需要定期显示每个组件唯一的新值(倒计时,时间戳,已用时间等).最自然的方法是创建使用RxJS timerinterval工厂函数的observable .但是,这些会在调用间隔函数时多次触发整个应用程序的每个间隔的角度变化检测.如果我们在页面上有许多组件,则会触发每秒或每个时间段对整个应用程序进行数十次检测,从而产生很大的性能开销.

到目前为止,我有两种尝试解决问题的方法.对这两者的一个好的答案将是非常有帮助的 - 理想的是两者.我想避免手动触发变化检测,而是依赖于Observables发出的新值,并让异步管道/ OnPush变化检测策略负责触发变化检测.如果这是不可能的,我想了解原因.

  1. 有没有办法禁用或阻止RxJS timerinterval函数触发角度变化检测?使用NgZone zone.runOutsideAngular(() => this.interval$ = interval(1000) ... )似乎不会这样做.StackBlitz示例:https://stackblitz.com/edit/angular-zo5h39
  2. 或者,如果我使用RxJS Subject结合setInterval被调用的内部创建一个Observable流zone.runOutsideAngular,为什么在从主题发出新值时不会为子组件触发更改检测?StackBlitz示例:https://stackblitz.com/edit/angular-yxdjgd

Max*_*kyi 8

  1. 有没有办法禁用或阻止RxJS计时器或间隔功能触发角度变化检测?使用NgZone zone.runOutsideAngular(()=> this.interval $ = interval(1000)...)似乎不会这样做.

这是因为observable很冷,而value producer(setInterval)只在订阅发生时执行.虽然此代码在Angular区域之外执行:

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

它实际上并没有立即调用interval运算符内的值生成器.稍后在IntervalInnerComponent订阅AsyncPipe时调用它.这发生在Angular区域内:

在此输入图像描述

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

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

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

  • 注入ChangeDetectorRef并手动触发组件及其祖先的变化检测
  • 注入ApplicationRef并手动触发整个应用程序的变更检测