最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Render time-based Observables in Angular without overwhelming change detection - Stack Overflow

programmeradmin0浏览0评论

We have a number of ponents in our Angular application that need to regularly display new values every second that are unique to each ponent (countdowns, timestamps, elapsed time, etc). The most natural way to is to create observables that use the RxJS timer and interval factory functions. However, these trigger Angular change detection at every interval for the entire app as many times as the interval function was called. If we have dozens of ponents on the page, this triggers change detection for the entire app dozens of times every second or time period, creating a large performance overhead.

So far there are two ways I've attempted to solve the problem. A good answer to either would be very helpful - ideally both. I want to avoid manual trigger of change detection and instead rely on new values emitted from Observables and have the async pipe/OnPush change detection strategy be responsible for triggering change detection. If this isn't possible, I'd like to understand why.

  1. Is there any way to disable or prevent RxJS timer or interval functions from triggering Angular change detection? Using NgZone zone.runOutsideAngular(() => this.interval$ = interval(1000) ... ) does not appear to do this. StackBlitz example:
  2. Alternatively, if I create an Observable stream using an RxJS Subject bined with setInterval called inside zone.runOutsideAngular, why isn't change detection triggered for the child ponent when a new value is emitted from the subject? StackBlitz example:

We have a number of ponents in our Angular application that need to regularly display new values every second that are unique to each ponent (countdowns, timestamps, elapsed time, etc). The most natural way to is to create observables that use the RxJS timer and interval factory functions. However, these trigger Angular change detection at every interval for the entire app as many times as the interval function was called. If we have dozens of ponents on the page, this triggers change detection for the entire app dozens of times every second or time period, creating a large performance overhead.

So far there are two ways I've attempted to solve the problem. A good answer to either would be very helpful - ideally both. I want to avoid manual trigger of change detection and instead rely on new values emitted from Observables and have the async pipe/OnPush change detection strategy be responsible for triggering change detection. If this isn't possible, I'd like to understand why.

  1. Is there any way to disable or prevent RxJS timer or interval functions from triggering Angular change detection? Using NgZone zone.runOutsideAngular(() => this.interval$ = interval(1000) ... ) does not appear to do this. StackBlitz example: https://stackblitz./edit/angular-zo5h39
  2. Alternatively, if I create an Observable stream using an RxJS Subject bined with setInterval called inside zone.runOutsideAngular, why isn't change detection triggered for the child ponent when a new value is emitted from the subject? StackBlitz example: https://stackblitz./edit/angular-yxdjgd
Share Improve this question asked Dec 4, 2018 at 17:04 Craig SmithamCraig Smitham 3,9734 gold badges35 silver badges43 bronze badges 0
Add a ment  | 

1 Answer 1

Reset to default 10
  1. Is there any way to disable or prevent RxJS timer or interval functions from triggering Angular change detection? Using NgZone zone.runOutsideAngular(() => this.interval$ = interval(1000) ... ) does not appear to do this.

It's because observables are cold and the value producer (setInterval) is only executed when a subscription happens. Read more here. Although this code is executed outside of Angular zone:

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

it doesn't actually immediately invoke the value producer inside interval operator. It will be later invoked when AsyncPipe in the IntervalInnerComponent subscribes. And this happens in inside Angular zone:

Using subject in the next alternative you make it hot and subscribe immediately outside of Angular zone.

  1. Alternatively, if I create an Observable stream using an RxJS Subject bined with setInterval called inside zone.runOutsideAngular... setInterval values are being created (they can be subscribed to manually), but the async pipe does not appear to be triggering change detection

Because Async Pipe doesn't trigger change detection. It simply marks a ponent and all its ancestors for check during the following change detection whenever it will be. See this answer or this article for more details. Zone.js triggers change detection. But since you're running setInterval outside Angular zone, it doesn't trigger it. Under this setup you have a few options:

  • inject ChangeDetectorRef and manually trigger change detection for the ponent and its ancestors
  • inject ApplicationRef and manually trigger change detection for the entire application
发布评论

评论列表(0)

  1. 暂无评论