在Angular中渲染基于时间的Observable,而无需压倒性的变化检测

时间:2018-12-04 17:04:26

标签: javascript angular rxjs angular-changedetection

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

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

  1. 是否有任何方法可以禁用或阻止RxJS timerinterval函数触发角度变化检测?使用NgZone zone.runOutsideAngular(() => this.interval$ = interval(1000) ... )似乎没有做到这一点。 StackBlitz示例:https://stackblitz.com/edit/angular-zo5h39
  2. 或者,如果我使用在Subject内调用的RxJS setIntervalzone.runOutsideAngular组合创建了一个Observable流,为什么当新值是从主体发出? StackBlitz示例:https://stackblitz.com/edit/angular-yxdjgd

1 个答案:

答案 0 :(得分:8)

  
      
  1. 是否有任何方法可以禁用或阻止RxJS计时器或间隔函数触发角度变化检测?使用NgZone   zone.runOutsideAngular(()=> this.interval $ = interval(1000)...)   似乎没有这样做。
  2.   

这是因为可观察变量很冷,并且只有在发生订阅时才执行值生产者(setInterval)。尽管此代码是在Angular区域之外执行的:

  

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

它实际上并不会立即调用interval运算符内部的值生成器。稍后IntervalInnerComponent中的AsyncPipe订阅时将调用它。这发生在Angular区域内:

enter image description here

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

  
      
  1. 或者,如果我使用RxJS主题与setInterval结合使用创建了一个Observable流,该setInterval称为zone.runOutsideAngular ...正在创建setInterval值(可以订阅它们)   手动),但异步管道似乎并未触发更改   检测
  2.   

因为异步管道不会触发更改检测。它只是标记了组件及其所有祖先,以便在以后进行更改检测时进行检查。有关更多详细信息,请参见此answerthis article。 Zone.js触发更改检测。但是由于您在Angular区域之外运行setInterval,所以它不会触发它。在此设置下,您有几个选择:

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