我们的Angular应用程序中有很多组件,需要每秒定期显示每个组件唯一的新值(倒数,时间戳,经过的时间等)。最自然的方法是创建使用RxJS timer
和interval
工厂函数的可观察对象。但是,它们会在整个间隔调用间隔函数的整个时间间隔内触发整个角度的角度变化检测。如果页面上有数十个组件,则每秒或整个时间段触发整个应用数十次更改检测,从而产生较大的性能开销。
到目前为止,我已经尝试了两种方法来解决该问题。一个好的答案将是非常有帮助的-理想的情况是两个。我想避免手动触发变更检测,而要依赖于Observables发出的新值,并让异步管道/ OnPush变更检测策略负责触发变更检测。如果这不可能,我想了解原因。
timer
或interval
函数触发角度变化检测?使用NgZone zone.runOutsideAngular(() => this.interval$ = interval(1000) ... )
似乎没有做到这一点。 StackBlitz示例:https://stackblitz.com/edit/angular-zo5h39 Subject
内调用的RxJS setInterval
与zone.runOutsideAngular
组合创建了一个Observable流,为什么当新值是从主体发出? StackBlitz示例:https://stackblitz.com/edit/angular-yxdjgd 答案 0 :(得分:8)
- 是否有任何方法可以禁用或阻止RxJS计时器或间隔函数触发角度变化检测?使用NgZone zone.runOutsideAngular(()=> this.interval $ = interval(1000)...) 似乎没有这样做。
这是因为可观察变量很冷,并且只有在发生订阅时才执行值生产者(setInterval)。尽管此代码是在Angular区域之外执行的:
()=> this.interval $ = interval(1000)...
它实际上并不会立即调用interval
运算符内部的值生成器。稍后IntervalInnerComponent
中的AsyncPipe订阅时将调用它。这发生在Angular区域内:
在下一个替代方案中使用主题,您可以使其变得热门并立即在Angular区域之外进行订阅。
- 或者,如果我使用RxJS主题与setInterval结合使用创建了一个Observable流,该setInterval称为zone.runOutsideAngular ...正在创建setInterval值(可以订阅它们) 手动),但异步管道似乎并未触发更改 检测
因为异步管道不会触发更改检测。它只是标记了组件及其所有祖先,以便在以后进行更改检测时进行检查。有关更多详细信息,请参见此answer或this article。 Zone.js触发更改检测。但是由于您在Angular区域之外运行setInterval
,所以它不会触发它。在此设置下,您有几个选择:
ChangeDetectorRef
并手动触发组件及其祖先的更改检测ApplicationRef
并手动触发整个应用程序的更改检测